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地址:https://mvnrepository.com/。
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)基于注解方式创建对象
5.2使用spring注入属性
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方法可以看到在控制台的打印结果