Spring总结

 1.什么是spring?

Spring是一个分层的一站式轻量级开源框架。

2.spring入门

项目地址:https://github.com/zhongyushi-git/spring-collection.git。下载代码后,示例代码在spring5-demo文件夹下。本项目是以原生的jar方式介绍的,同步的maven版本的代码见https://www.cnblogs.com/zys2019/p/14538440.html。

2.1Spring的jar下载与导入

如果要使用spring中的东西,就必须被spring管理。

官网:spring.io,下载地址:https://repo.spring.io/release/org/springframework/spring/,下载对应版本,在下载时只需要下载以.dist.zip结尾的压缩包即可,这里以5.3.4为例:

下载好之后,打开libs文件夹,里面是所有的jar包

其他下载jar地址:

2.2使用spring调用对象的方法案例

1.使用idea新建一个普通的java项目

2.在项目下新建lib文件夹,把以下jar包复制到lib中

3.选择File->Project Structure..,按下图进行操作

 4.选择所有的jar,点击确定

 5.导入后如下图

6.编写配置文件。在src下新建一个applicationContext.xml的文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


</beans>

7.创建一个hello的类,在里面写一个方法:

package com.test;

public class Hello {
    public void say(){
        System.out.println("hello,goodmonring");
    }
}

8.修改配置文件applicationContext.xml,让其交给spring管理:

<!--bean将某个java对象交给spring管理,id是给bean取名,class指定要被管理的类的路径-->
<bean id="hello" class="com.test.Hello"></bean>

9.新建一个测试了哦进行测试测试:

package com.test;

import com.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

@Test
public void helloTest() {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean对象,其中hello就在xml中指定的id值
Hello hello = context.getBean("hello", Hello.class);//第一种方式,指定class
// Hello hello = (Hello)context.getBean("hello");//第二种方式,转换为指定类,两种方式都可以
//调用方法
hello.say();
}

}

10.运行测试方法,会发现出现了错误,原因是没有导入日志的jar。

11.只需要把commons-logging-1.1.1.jar导入进来即可,jar在项目lib文件夹中。导入后再执行就会在控制台打印相应的结果。本案例并没有使用new方式创建对象,而是使用spring方式。

3. IOC快速入门

3.1.原理

IOC:inversion of Controller(控制反转),把对象的控制权交给spring。原来由我们自己实例化的对象交给spring容器来实例化,这时对象的实例化的权利就会反转,降低耦合度。上面的案例就是使用IOC控制反转方式来操作的。

3.2.实现方式(接口)

1)BeanFactory

IOC容器最基本实现,是Spring内部的使用接口,不提供开发使用。在加载配置文件时,不会创建对象,只有在获取(使用)对象时才会创建。

2)ApplicationContext

是BeanFactory的子接口,功能更强大,供开发使用。在加载配置文件时,就会创建对象。

3.3.ApplicationContext的实现类

实现类有两个,如下图:(使用Ctrl+H查看实现类)

1)FileSystemXmlApplicationContext:使用这种方式xml可以放在磁盘的任何位置,但需要指定xml的全路径。

2)ClassPathXmlApplicationContext:使用这种方式必须让xml文件在src资源目录下,否则找不到。

4.DI快速入门

DI:dependency injection 依赖注入。在spring框架负责创建Bean对象时,动态将依赖对象注入到Bean组件中,简单的说就是给对象的属性注入值。下面是对User的属性赋值案例:

4.1 通过属性注入值

注意:通过属性注入值时,此对象必须有set方法,否则注入不进去。

第一步:创建user对象,添加get和set方法

package com.entity;

public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第二步:把user交给spring管理并通过属性注入值

<bean id="user" class="com.entity.User">
    <!--通过属性注入值,必须提供get和set方法-->
    <property name="name" value="元慧"></property>
    <property name="age" value="23"></property>
 </bean>

第三步:测试方法

@Test
public void test1(){
    //加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取bean对象
    User user = (User) context.getBean("user");
    //调用方法
    System.out.println(user.toString());
}

执行测试方法后,打印的就是注入的值,如下图:

第四步:分析。

在注入时使用的property标签,name指定的是要注入的属性的名称,value是要注入的值。

<property name="age" value="23"></property>

 此行代码就是把23注入到对象User的age属性上,相当于user.setAge(20)。  

4.2 通过构造方法注入值

注意:通过构造方法注入时,此类必须有有参构造。

第一步:给User对象添加有参构造(以User2说明)

package com.entity;

public class User2 {
    private String name;
    private int age;

    public User2(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第二步:把user交给spring管理并通过构造方法注入值

 <bean id="user2" class="com.entity.User2">
        <!--构造注入内容,必须提供有参构造-->
        <constructor-arg name="name" value="123"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
 </bean>

第三步:测试方法

 @Test
    public void test2() {
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        User2 user = (User2) context.getBean("user2");
        //调用方法
        System.out.println(user.toString());
    }

以上对象的属性是简单数据类型String和Integer类型的,也就是介绍了简单对象的属性注入,而其他对象的属性注入见后续章节。

第四步:分析。

在注入时使用的constructor-arg标签,name指定的是要注入的属性的名称,value是要注入的值。

4.3 注入特殊符号

当在xml中注入的值包含特殊符号时,可以使用CDATA。用法如下:

 <bean id="user" class="com.entity.User">
        <!--通过属性注入值,必须提供get和set方法-->
        <property name="name" >
            <value><![CDATA[<你好啊>]]></value>
        </property>
        <property name="age" value="23"></property>
    </bean>

把value单独拿出来作为标签,包含特殊符号的值放在CDATA的第二个中括号中。执行结果是User{name='<你好啊>', age=23}。

4.4 面试题IOC和DI区别?

IOC 控制反转,是指对象实例化权利由spring容器来管理

DI 依赖注入,在spring创建对象的过程中,对象所依赖的属性通过配置注入对象中。

5.Bean管理

Spring中有两种bean,一种是普通bean,即在配置文件中定义的bean和返回的类型一致;另一种是工厂bean(FactoryBean),它在配置文件中定义的bean可以和返回的类型不一养。默认创建的是单实例对象。

Bean管理就是Spring自身创建对象,再使用Spring来注入属性。

5.1使用spring创建对象

1)基于xml方式创建对象

入门案例中的xml配置就是基于这种方式

<bean id="hello" class="com.test.Hello"></bean>

其中id是唯一标识,用于获取对象,class是指定类的路径。它在创建对象时会默认执行无参构造方法。

2)基于注解方式创建对象

详见第7章节。

5.2使用spring注入属性

详见第6章节。

5.3xml自动装配

定义:根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入。

自动装配使用autowire属性,值有两种,分别是byName和byType。

byName:根据属性名称来装配,也就是说对象的属性名要和bean的id值一样,才能注入成功

byType:根据属性类型来装配,也就是说对象的属性类型要和bean的class的类型一致。如果在配置文件中有多个类型都是一样的,那么使用此方式就会报错。

在上述的案例中对象Car有属性user是User类型的,以此为例说明,下面两行代码分别是两种装配方式:

<bean id="car2" class="com.entity.Car" autowire="byName"></bean>

<bean id="car2" class="com.entity.Car" autowire="byType"></bean>

上述装配一般不会使用,只做介绍。

6.Spring属性注入

6.1基于xml方式注入

简单属性的注入在第4章已经介绍,这里介绍其他的类型属性注入。

为了方便,后面的实体类均省略getter、setter和toString方法。

1.ref的使用

在一个实体类中持有另一个实体类的引用,就可以用到ref属性。ref的值是要引用的对象的bean的id。

1)新建car类

package com.entity;

public class Car {
private String brand;
private double price;
private User user;
}

2)在xml中注入值

<bean id="user" class="com.entity.User">
     <!--通过属性注入值,必须提供get和set方法-->
    <property name="name" value="元慧"></property>
    <property name="age" value="23"></property>
 </bean>
<bean id="car" class="com.entity.Car">
    <property name="brand" value="迈巴赫"></property>
    <property name="price" value="8000000"></property>
    <property name="user" ref="user"></property>
  </bean>

3)测试方法

@Test
public void test3(){
    //加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取bean对象
    Car car = (Car) context.getBean("car");
    //调用方法
    System.out.println(car);
}

执行结果:

Car{brand='迈巴赫', price=8000000.0, user=User{name='元慧', age=23}}

4)使用内部bean注入

通过ref的方式是使用的外部bean方式,也就是说引用的bean都是定义好并指定了id,而内部bean是写在内部的,无需id值。把上述注入改成:

    <bean id="car" class="com.entity.Car">
        <property name="brand" value="迈巴赫"></property>
        <property name="price" value="8000000"></property>
        <property name="user">
            <bean class="com.entity.User">
                <property name="name" value="郭慧"></property>
                <property name="age" value="20"></property>
            </bean>
        </property>
    </bean>

在注入user属性时,在内部写了一个bean标签来输注入User对象的属性。内部属性注入的方式并没有外部的清晰,用的较少。

2.集合属性的注入

集合类型的属性只介绍List、Set和Map类型。

1)创建实体类

实体类包含两种,一种是String类型,代表基本类型;另一种是User类型,代表对象类型。测试方法在代码中,在此略。

基本类型实体:

package com.entity;

import java.util.List;
import java.util.Map;
import java.util.Set;
public class Coll {
private List<String> listStr;
private Set<String> setStr;
private Map<String, String> mapStr;
private Map<String, List<String>> mapList;
}

对象类型实体:

package com.entity;

import java.util.List;
import java.util.Map;
import java.util.Set;
public class Coll2 {
private List<User> userList;
private Set<User> userSet;
private Map<String, User> userMap;
private Map<String, List<User>> mapList;
}

2)属性注入

A:List类型

数组类型的注入和List类似,只需要把list标签改为array标签即可,使用list标签也是可以的。

(1)基本类型注入:

<bean id="coll" class="com.entity.Coll">
    <property name="listStr">
        <list>
            <value>张三</value>
            <value>李四</value>
            <value>王五</value>
            <value>张三</value>
        </list>
    </property>
</bean>

(2)实体类型注入:

注入实体类型时,使用ref标签,bean的值就是对象的bean的id值。

<bean id="user" class="com.entity.User">
    <!--通过属性注入值,必须提供get和set方法-->
   <property name="name" value="元慧"></property>
   <property name="age" value="23"></property>
</bean>
<bean id="user3" class="com.entity.User">
    <property name="name" value="郭慧"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="coll2" class="com.entity.Coll2"> <property name="userList"> <list> <ref bean="user"></ref> <ref bean="user3"></ref> </list> </property> </bean>

B:Set类型

1)基本类型注入:

<bean id="coll" class="com.entity.Coll">
<property name="setStr">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
<value>张三</value>
</set>
</property>
</bean>

(2)实体类型注入:

<bean id="user" class="com.entity.User">
    <!--通过属性注入值,必须提供get和set方法-->
   <property name="name" value="元慧"></property>
   <property name="age" value="23"></property>
</bean>
<bean id="user2" class="com.entity.User">
    <property name="name" value="郭慧"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="coll2" class="com.entity.Coll2">
<property name="userSet">
<set>
<ref bean="user"></ref>
<ref bean="user3"></ref>
</set>
</property>
</bean>

C:Map类型

1)基本类型注入:

<bean id="coll" class="com.entity.Coll">
<property name="mapStr">
<map>
<entry key="name" value="张三"></entry>
<entry key="sex" value="女"></entry>
<entry key="age" value="20"></entry>
</map>
</property>
</bean>

(2)实体类型注入:

<bean id="user" class="com.entity.User">
    <!--通过属性注入值,必须提供get和set方法-->
   <property name="name" value="元慧"></property>
   <property name="age" value="23"></property>
</bean>
<bean id="user2" class="com.entity.User">
    <property name="name" value="郭慧"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="coll2" class="com.entity.Coll2">
<property name="userMap">
<map>
<entry key="用户1" value-ref="user"></entry>
<entry key="用户2" value-ref="user3"></entry>
</map>
</property>
</bean>

D:组合类型

1)基本类型注入:

<bean id="coll" class="com.entity.Coll">
    <property name="list">
        <list>
            <value>张三</value>
            <value>李四</value>
            <value>王五</value>
            <value>张三</value>
        </list>
    </property>
</bean>

(2)实体类型注入:

<bean id="user" class="com.entity.User">
    <!--通过属性注入值,必须提供get和set方法-->
   <property name="name" value="元慧"></property>
   <property name="age" value="23"></property>
</bean>
<bean id="user3" class="com.entity.User">
    <property name="name" value="郭慧"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="coll" class="com.entity.Coll">
    <property name="list">
       <list>
           <ref bean="user"></ref>
           <ref bean="user3"></ref>
       </list>
    </property>
</bean>

3.外部属性文件注入

有些属性的值是需要配置的,也就是说属性的值会放到一个properties配置文件中,在xml中读取这个配置文件内容,然后把属性注入即可。下面以配置数据库连接池为例说明。

1)导入druid的jar(在lib中)

2)直接方式配置

 <!-- 数据库连接池 ,直接方式配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/community-manage" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>

这种方式虽然简单,但是值发生变化是还要来改xml文件,可以把配置提取出来。

3)外部属性文件配置

第一步:在src下新建db.properties,内容如下:

第二步:在beans中引入context的名称空间

 截图如上,做法是把beans的xmlns和http都复制一份,改成context即可。

第三步:把db.properties引入到xml配置文件中

<!-- 引入外部文件-->
<context:property-placeholder location="classpath:db.properties"/>

第四步:属性的注入。使用${}来注入属性,括号里面是外部文件中key值。

<!-- 数据库连接池 ,外部方式配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
</bean>

6.2基于注解方式注入

基于注解方式的注入内容较多,见第7章节。

7. spring注解开发

7.1什么是注解

注解是代码的特殊标记,可简化xml配置。格式:@注解名称(属性名称=属性值,属性名称=属性值...)。

7.2使用注解方式创建对象

在spring中针对bean创建对象的注解有:@Component、@Repository、@Service、@Controller。

@Component:在类的前面加上这个注解,就可以把它交给spring管理,不需要在xml中配置,相当于xml中配置一个<bean>标签。

@Repository:对Component的延伸,用于DAO层,便于区分

@Service:对Component的延伸,用于Service层,便于区分

@Controller:对Component的延伸,用于Controller层,便于区分

1)导入aop的jar。此jar包在下载的spring压缩包中有。在spring中使用注解必须进行包扫描,还要开启注解。为了代码清晰度,注解方式的配置文件以新建的applicationContext2.xml为例说明

2)在applicationContext2.xml文件中引入命名空间。

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

3)在applicationContext2.xml文件中开启注解,进行包扫描

<!--开启注解包扫描-->
<context:component-scan base-package="com.test"></context:component-scan>

其中指定了包是com.test,只要把所有注解的类放到com.test包下都可以被扫描到。

4)在com.test包下新建一个UserService类,加上@Component注解。

package com.test;

import org.springframework.stereotype.Component;

@Component
//@Component(value = "userService")
public class UserService {

    public void say(){
        System.out.println("userService执行了。");
    }
}

此注解可以指定一个value值,可省略,默认值是此类名并把首字母小写。如同上述代码,使用两种方式的注解都可以,其中value的值就是在xml中指定的bean的id值。

5)新建测试方法

   @Test
    public void test7(){
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
        //获取bean对象
        UserService userService=context.getBean("userService",UserService.class);
        //调用方法
        userService.say();
    }

执行测试方法,say方法正常执行。这就是使用注解注入对象。

6)开启包扫描细节问题

(1)当只指定了包名时,spring会扫描此包下面所有的类,也可以设置只扫描指定的类。

<!--开启注解包扫描,只扫描controller-->
    <context:component-scan base-package="com.test" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

上述代码就指定了只扫描controller类,即注解是@Controller的类。

(2)除了指定要扫描的类之外,也可以设置哪些类不进行扫描

<!--开启注解包扫描,不扫描controller-->
    <context:component-scan base-package="com.test">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

include-filter是包含的,exclude-filter是不包含的。

7.3使用注解方式注入属性

在spring中针对bean属性注入的注解有:@Autowired、@Qualifier、@Resource、@Value。

@Autowired:根据属性类型进行自动注入,注入复杂类型的值

@Qualifier:根据属性名称进行注入,可以解决一个类有多个子类而找不到具体哪一个类的问题

@Resource:根据属性类型换名称进行注入。是上面两个注解的合并

@Value:根据属性名称进行注入,注入简单类型的值

1)新建UserDao类,添加注解

package com.test;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public void add(){
        System.out.println("我是userDao的add方法");
    }
}

2)在UserService中注入UserDao并调用add方法

package com.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
//@Component(value = "userService")
public class UserService {

    public void say(){
        System.out.println("userService执行了。");
    }

    @Autowired
    private UserDao userDao;

    public void add(){
        userDao.add();
    }
}

要使用@Qualifier,那么必须和@Autowired一起使用,

@Autowired
@Qualifier("userDao")
private UserDao userDao;

它们也可以替换为@Resource

@Resource(name = "userDao")
private UserDao userDao;

3)新建测试方法,调用add方法

 @Test
    public void test8(){
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
        //获取bean对象
        UserService userService=context.getBean("userService",UserService.class);
        //调用方法
        userService.add();
    }

执行结果:我是userDao的add方法。

4)@Value的使用

把括号里面的值注入给变量

 @Value("123")
private String name;

这种方式就可以把123赋值给name,此时name就有值了。这个注解主要用在读取properties文件内容。

7.4全注解方式开发

全注解方式就是说不要xml配置文件,使用注解来替代xml配置文件。

1)新建config包,在包下新建SpringConfig类,添加两个注解

package com.test.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//此注解表示此类是一个配置类,可代替xml配置文件
@Configuration
//开启注解进行包扫描
@ComponentScan(basePackages = {"com.test"})
public class SpringConfig {
}

2)新建测试方法

 @Test
    public void test9() {
        //加载配置类
        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取bean对象
        UserService userService = context.getBean("userService", UserService.class);
        //调用方法
        userService.add();
    }

这样方式并没有使用xml,仍然可以实现对象的创建和属性的注入。

8.SpringAOP

8.1aop概述

1)定义

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。主要用来记录日志。

2)AOP与OOP区别

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。换而言之,OOD/OOP面向名词领域,AOP面向动词领域。

3)底层原理

底层使用的是动态代理,有两种方式,分别是JDK代理(用于有接口的情况)和CGLIB代理(用于没有接口的情况)。

JDK代理:需要创建当前接口实现类的代理对象

CGLIB代理:需要创建当前类的子类代理对象

8.2 aop入门

8.2.1准备工作

为了代码的清晰度,在src下新建一个配置文件applicationContext3.xml

1)导入相关的jar包(在项目lib中)

 

 

 2)在applicationContext3.xml中配置

 引入命名空间:

xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"

引入约束:

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

8.2.2.使用xml方式配置

1)新建包com.controller,然后新建目标类StudDao

package com.controller;

public class StuDao {
public void add(){
System.out.println("操作数据库啦");
}
}

2)编写增强类StuHelper,这个类用于在add方法调用之前执行:

package com.controller;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class StuHelper implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("我是增强类的before方法");
}
}

3)修改applicationContext3.xml:

<!--交给spring管理-->
<bean class="com.controller.StuDao" id="StuDao"></bean>
<bean class="com.controller.StuHelper" id="StuHelper"></bean>
<!--aop配置-->
<aop:config>
<!--配置切点
expression="execution(* com.controller.StuDao.add(..))"
切点表达式,*表示返回值类型,..表示任意参数-->
<aop:pointcut id="addPoint" expression="execution(* com.controller.StuDao.add(..))"/>
<!--当调用add方法时通知hepler-->
<aop:advisor advice-ref="StuHelper" pointcut-ref="addPoint"></aop:advisor>
</aop:config>

4)新建测试类进行测试:

package com.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext3.xml")
public class StuTest {

@Autowired
private StuDao dao;

@Test
public void test(){
dao.add();
}
}

输出结果:

我是增强类的before方法
操作数据库啦

8.2.3整合aspect

1)自定义增强类:

package com.controller;

public class Helper {
    public void before(){
        System.out.println("before方法");
    }
    public void after(){
        System.out.println("after方法");
    }
}

2)修改applicationContext.xml:

<!--交给spring管理-->
<bean class="com.controller.StuDao" id="StuDao"></bean>
<bean class="com.controller.Helper" id="helper"></bean>
<!--aop配置-->
<aop:config>
<aop:aspect ref="helper">
<aop:pointcut id="addCut" expression="execution(* com.controller.StuDao.add(..))"/>
<aop:before method="before" pointcut-ref="addCut"></aop:before>
<aop:after method="after" pointcut-ref="addCut"></aop:after>
</aop:aspect>
</aop:config>

3)测试:测试输出的结果是    before方法,操作数据库啦,after方法

8.2.4.使用注解方式配置

1)修改applicationContext3.xml:

<!--配置aop代理-->
<aop:aspectj-autoproxy/>
<!--开启注解扫描-->
<context:component-scan base-package="com.controller" />

2)编写目标类StuDao2:

package com.controller;

import org.springframework.stereotype.Repository;

@Repository
public class StuDao2 {

public void add(){
System.out.println("操作数据库啦");
}
}

3)编写增强类:

package com.controller;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class Helper2 {

@Before(value = "execution(* com.controller.StuDao2.add(..))")
public void before(){
System.out.println("before方法");
}

@After(value = "execution(* com.controller.StuDao2.add(..))")
public void after(){
System.out.println("after方法");
}
}

4)新建测试方法,测试结果同上。

8.2.5其他通知类型

1)后置通知

//后置通知
@AfterReturning(value = "execution(* com.controller.StuDao2.add(..))", returning = "value")
public void afterReturn(JoinPoint jp, Object value) {
System.out.println("后置通知的返回值是" + value);
}

2)环绕通知

//环绕通知
@Around(value = "execution(* com.controller.StuDao2.add(..))")
public Object around(ProceedingJoinPoint jp) throws Throwable {
Object o = jp.proceed();
return o;
}

2)异常通知(常用):

//异常通知
@AfterThrowing(value = "execution(* com.controller.StuDao2.add(..))", throwing = "e")
public void afterThrow(Throwable e) {
System.out.println(e);
}

8.3.Scope注解

@Scope它以描述bean的作用域(单例或多例)。

Singleton:单例模式,内存中只会有一个该对象,是默认的模式。

Prototype:多例模式,每次使用都初始化一个新的对象。一般用在controller或service层,增加访问带宽

@Repository
@Scope("Prototype")
//指定为多例模式
public class StuDao {
   ...
}

此代码只做介绍。   

9.spring5新功能

9.1整合日志框架Log4j2

在spring5中自带了日志框架,可与log4j2结合使用,下面就介绍spring5整合日志框架。

1)导入jar(在项目的lib)

 2)在src中创建log4j.xml,此名称是固定的

<?xml version="1.0" encoding="UTF-8" ?>
<!--日志级别以及优先级排序:OFF>FATAL>ERROR>WARN>INFO>DEBU6>TRACE>ALL-->
<!--configuration后面的status用于设置log4 2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4.j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-M-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

3)新建一个UserLog类用于测试

package com.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserLog {

    private static final Logger log= LoggerFactory.getLogger(UserLog.class);

    public static void main(String[] args) {
        log.info("你好啊");
    }
}

执行main方法可以看到在控制台的打印结果

posted @ 2019-08-31 14:27  钟小嘿  阅读(274)  评论(0编辑  收藏  举报