Spring概述
Spring是一个分层的java SE/EE 全站轻量级框架,它以IoC(Inversion of Control 控制反转)和AOP(Aspect Oriented Programming面向切面编程)为内核,使用基本的javaBean来完成以前只能由EJB(Enterprise Java Beans,Java企业Bean)完成的工作。
Spring 的下载及目录结构
Spring 开发所需的Jar包分为两部分,具体如下。这里以Spring 4.3.6为例
- Spring框架包
下载地址:http://repo.spring.io/simple/libs-release-local/org/springframework/spring/4.3.6.RELEASE/
文件名称:spring-framework-4.3.6.RELEASE-dist
解压后的文件目录
- docs文件夹中包含Spring的API文档和开发规范;
- libs文件夹中包含开发需要的JAR包和源码;
- schema文件夹中包含开发所需要的schema文件,这些文件定义了Spring相关配置文件的约束
在libs目录中,有四个Spring的基础包,分别对应Spring核心容器的四个模块:
- spring-core-4.3.6.RELEASE.jar: 包含Spring框架基本的核心工具类,Spring 其他组件都要用到这个包里的类,是其他组件的基本核心。
- spring-beans-4.3.6.RELEASE.jar: 所有应用都要用到的JAR包,它包含访问配置文件、创建和管理Bean以及进行Inversion of Control(loC)或者 Dependency Injection(DI)操作相关的所有类。
- spring-context-4.3.6.RELEASE.jar: Spring 提供了在基础loC功能上的扩展服务,还提供了许多企业级服务的支持,如邮件服务、任务调度、 JNDI 定位、 EJB 集咸、远程访问、缓存以及各种视图层框架的封装等。
- spring-expression-4.3.6.RELEASE.jar: 定义了Spring的表达式语言。
- 第三方依赖包
Spring核心容器还需要依赖commons.logging的jar包,地址:http://commons.apache.org/proper/commons-loggingdownload_logging.cgi
Spring核心容器
Spring框架主要功能是通过其核心容器来实现,Spring框架提供了两种核心容器:BeanFactory和ApplicationContext。
BeanFactory
BeanFactory 由 org.springframework.beans.facytory.BeanFactory 接口定义,是基础类型的 loC 容器.BeanFactory是一个管理Bean工厂,主要负责初始化各种Bean和调用它们的生命周期方法。
BeanFactory提供的几个实现类中,最长常用的是org.springframework.beansfactory.xml.XmIBeanFactory,该类会根据xml的配置文件中的定义来装配Bean.
BeanFactory beansFactory=new XmlBeanFactory(new FileSystemResource("F:/applicationContext.xml"));
ApplicationContext
ApplicationContext是BeanFactory的子接口,是另一种Spring核心容器。它由 org.springframework.context.ApplicationContext 接口定义,不仅包含了BeanFactory 的所有功能,还添加了对国际化、资源访问、事件传播等方面的支持。
创建ApplicationContext接口实例,通常有2中方法:
- 通过ClassPathXmlApplicationContext创建
String xmlPath= "applicationContext.xml";
ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);
- 通过FileSystemXmlApplicationContext创建
ApplicationContext applicationContext=new FileSystemXmlApplicationContext(String configLocation);
与 ClassPathXmlApplicationContext 有所不同的是,FileSystemXmlApplicationContext 不再从类路径 中读取配置文件,而是通过参数指定配置文件的位置,例如 “0:/workspaces/appIicationContext.xm 1”。
- web中实例化ApplicationContext
在web项目中,ApplicationContext容器的实例化工作交由Web服务器来完成。Web服务器通过ContextLoaderListener方式来实例化,在web.xml中添加代码:
<!… 指定 Spring 配置文件的位置,多个配置文件时,以逗号分隔一〉
<context-param>
<param-name>contextConfigLocation</param-name>
<!一 Spring 将加载 spring 目录下的 applicationContext .xml 文件一 〉
<param-value>
classpath:spring/applicationContext.xml
</param-value>
<context-param>
<!一指定以 ContextLoaderListener 方式启动 Spring 容器 一〉
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
创建 Spring 容器后,就可以获取 Spring 容器中的 Bean。Spring 获取 Bean 的实例通常采用以下两种方法。
- Object getBean(String name): 根据容器中 Bean 的id或name来获取指定的 Bean ,获取之后需要进行强制类型转换。
- T getBean(Class requiredType) : 根据类的类型来获取Bean 的实例。由于此方法为泛型方法,因此在获取 Bean 之后不需要进行强制类型转换。
Spring入门案例
- 导入四个基础包和日志包
- cn.edu.sicau.ioc包下创建UserDao接口类
public interface UserDao {
public void say();
}
- 实现类 UserDaoImpl
public class UserDaoImpl implements UserDao{
@Override
public void say() {
System.out.println("userDao say hello World!");
}
}
- 在ioc包下创建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-4.3.xsd">
<!--配置目标类-->
<bean id="userDao" class="cn.edu.sicau.ioc.UserDaoImpl"/>
</beans>
- 在ioc包下创建测试类IoCTest
@Test
public void funcIoc1(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("cn/edu/sicau/ioc/applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.say();
}
运行结果:
依赖注入
依赖注入的概念
依赖注入和反向控制的含义相同,是从两个不同角度描述同一个概念。
当一个Java对象(调用者)需要调用另一个Java对象(被调用者)时,在传统模式下,调用者通常采用“new 被调用者”的代码来创建对象,
流程图语法(https://mermaidjs.github.io/flowchart.html)
使用Spring框架后,对象的实例不再由调用者创建,而是由Spring容器来创建。控制权由应用程序转移到了Spring容器,控制权发生了反转,这就是Spring的控制反转。
从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它的依赖实例,这就是Spring的依赖注入。
依赖注入的两种实现方式
属性setter方法注入:
IoC容器使用setter方法注入被依赖的实例
- 在Spring入门实例的基础上在ioc包下创建UserService接口类
public interface UserService {
public void say();
}
- 在ioc包下创建UserServiceImpl实现类
public class UserServiceImpl implements UserService{
private UserDao UserDao;
//setter方法
public void setUserDao(UserDao UserDao) {
this.UserDao = UserDao;
}
@Override
public void say() {
this.UserDao.say();
System.out.println("UserService say Hello World!");
}
}
- 在配置文件中创建一个id为userService的Bean,该Bean用于实例化UserServiceImpl,并将UserDao的实例注入到userService中。
<bean id="userService" class="cn.edu.sicau.ioc.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
- 测试类
@Test
public void funcIoc2(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("cn/edu/sicau/ioc/applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.say();
}
运行结果:
构造方法注入
IoC使用构造方法注入被依赖的实例
对应的在配置文件中
<!--<property name="userDao" ref="userDao"/>-->
<constructor-arg name="UserDao" ref="userDao"/>
Spring中的Bean
Bean的配置
Spring容器支持XML和Properties两种格式的配置文件,其中xml配置最常用。XML配置文件中根元素是,包含多个子元素,每个子元素定义了一个Bean。的常用属性及子元素如下:
[外链图片转存失败(img-eIgcoQkR-1564703784760)(assets/spring-425e31a0.png)]
Bean的实例化
实例化Bean有三种方式,分别:构造器实例化、静态工厂实例化、实例工厂实例化。
构造器实例化
构造器实例化指通过Bean对应类中的默认无参构造函数方法来实例化Bean。
案例
- Bean1
public class Bean1(){
}
- 配置文件
<?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-4.3.xsd">
<!--配置目标类-->
<bean id="bean1" class="cn.edu.sicau.ioc.Bean1"/>
</beans>
这里测试类就省略
静态工厂方式实例化
通过创建一个静态工厂的方法来创建Bean实例,其中Bean配置的class属性不再是Bean实例的实现类,而是静态工厂类,同时使用factory-method属性来指定所创建的静态工厂方法。
- 创建Bean2类,与上例中的Bean1类一样
2.创建静态工厂类 MyStaticFactory()来返回Bean2
public class MyStaticFactory {
public static Bean2 createBean(){
return new Bean2();
}
}
- 创建bean2.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-4.3.xsd">
<bean id="bean2" class="cn.edu.sicau.instance.static_factory.MyStaticFactory"
factory-method="createBean"/>
</beans>
- 测试类
@Test
public void func(){
ClassPathXmlApplicationContext applicationContext=new
ClassPathXmlApplicationContext("cn/edu/sicau/instance/static_factory/Bean2.xml");
Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
System.out.println(bean2);
}
实例工厂方式实例化
在配置文件中实例化Bean,不使用class属性直接指向实例化类,而是通过factory-bean属性指向配置的实例工厂,然后使用factory-method属性确定使用工厂中的那个方法。
实例
- 创建Bean3,与上例中的Bean1一样
- 创建实例工厂类Factory
public class Factory {
//创建Bean3实例的方法
public Bean3 createBean(){
return new Bean3();
}
}
- 配置文件
<?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-4.3.xsd">
<!-- 配置工厂 -->
<bean id="myFactory" class="cn.edu.sicau.instance.factory.Factory"/>
<!--使用factory-bean 指向实例化工厂
使用factory-method确定使用工厂中的那个方法-->
<bean id="bean3" factory-bean="myFactory" factory-method="createBean"/>
</beans>
Bean的装配方式
Spring容器常用三种Bean的装配方式,如基于XML的装配、基于注解装配、自动装配(其中基于注解最常用)。
基于XML的装配
Spring提供了2种XML的装配方式:设值注入(Setter Injection)和构造注入(Constructor Injection).
在实例化Bean的过程中,Spring首先会调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用setter方法来注入属性值。所以设值注入要求一个Bean必须满足一下两点:
- Bean类必须提供一个默认的无参构造方法
- Bean类必须为需要注入属性提供对应的setter方法
使用设值注入时,配置文件中元素使用子元素来为每个属性注入值;构造注入时,元素使用子元素来定义构造方法的参数,可以使用value或子元素来设置参数值。
实例:两种方式同时演示
- 创建User类
public class User {
private String username;
private Integer password;
private List<String> list;
/*
无参构造函数
设值注入
*/
public User(){
super();
}
/*
有参构造函数
构造注入
*/
public User(String username, Integer password, List<String> list) {
this.username = username;
this.password = password;
this.list = list;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(Integer password) {
this.password = password;
}
public void setList(List<String> list) {
this.list = list;
}
}
- 配置文件
<?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-4.3.xsd">
<!--构造注入-->
<bean id="user1" class="cn.edu.sicau.ioc.User">
<constructor-arg index="0" value="张三"/>
<constructor-arg index="1" value="123"/>
<constructor-arg index="2">
<list>
<value>"constructor1"</value>
<value>"constructor2"</value>
<value>"constructor3"</value>
</list>
</constructor-arg>
</bean>
<!--设值注入-->
<bean id="user2" class="cn.edu.sicau.ioc.User">
<property name="username" value="李四"/>
<property name="password" value="456"/>
<property name="list" >
<list>
<value>"setListValue1"</value>
<value>"setListValue2"</value>
</list>
</property>
</bean>
</beans>
- 测试类
@Test
public void funcIoc3(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("cn/edu/sicau/ioc/UserBean.xml");
User user1 = (User) applicationContext.getBean("user1");
User user2 = (User) applicationContext.getBean("user2");
System.out.println(user1);
System.out.println(user2);
}
测试结果
基于Annotation的装配
常用注解
- @Component:用来描述Spring中的Bean,可以作用在任何层次,仅仅标识一个组件(Bean)。
- @Repository: 用于将数据访问层(DAO层)的类标识为Spring中的Bean,其功能与@Component相同。
- @Service:用于业务层(Service层),用于将业务层的类标识为Bean,其功能与@Component相同。
- @Controller:用于控制层的类标识为Bean,其功能与@Component相同。
- @Autowired: 用于对 Bean 的属性变量、属性的 setter 方法及构造方法进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。 默认按照 Bean 的类型进行装配。
• @Resource: 其作用与@Autowired一样。其区别在于@Autowired 默认按照Bean类型装配,而@Resource 默认按照 Bean 实例名称进行装配。@Resource 中有两个重要属性: name和type。Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为Bean实例类型。如果指定name属性,则按实例名称进行装配;如果指定type属性,则按Bean类型进行装配;如
果都不指定,则先按 Bean 实例名称装配,如果不能匹配,再按照Bean类型进行装自己;如果都无法匹配,则抛出NoSuchBeanDefinitionException 异常 。
• @Qualifier: 与@Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为接 Bean
的实例名称装配, Bean 的实例名称由 @Qualifier 注解的参数指定 。
实例
Spring 4.0 以上版本使用上面的代码对指定包中的注解进行扫描前,需要先向项目中导入 Spring AOP 的 JAR 包 spring-aop-4.3.6.RELEASE.jar,否则程序在运行时会报出 “java.lang.NoClassDefFound Error: orglspringframeworklaop/TargetSource” 错误。
- 在annotation包下创建DAO层接口:UserDao
public interface UserDao {
void save();
}
- 在annotation包下创建DAO层实现类:UserDao实现类UserDaoImpl
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Override
public void save() {
System.out.println("userDao ……save……");
}
}
使用 @Repository 注解将 UserDaolmpl 类标识为 Spring 中的 Bean,其写法相当于配置文件中 的编写
- 在annotation包下创建业务层接口:userService
public interface UserService {
void save();
}
- 在annotation包下创建业务层实现类:UserServiceImpl
//标识Bean
@Service("userService")
public class UserServiceImpl implements UserService{
//这相当于配置文件中 <property name="userDao" ref="userDao"/> 的写法
@Resource(name = "userDao")
private UserDao userDao;
@Override
public void save() {
userDao.save();
System.out.println("userService …… save ……");
}
}
- 在annotation包下控制层创建UserController
//标识Bean
@Controller("userController")
public class UserController {
//<property name="userService" ref="userService" /
@Resource(name = "userService")
private UserService userService;
public void save(){
userService.save();
System.out.println("userController …… save ……");
}
}
- 在annotation包下创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--使用context命名空间,在配置文件中开启注解处理器-->
<!--<context:annotation-config/>-->
<!--定义3个bean-->
<!--<bean id="userDao" class="cn.edu.sicau.annotation.UserDaoImpl"/>
<bean id="userService" class="cn.edu.sicau.annotation.UserServiceImpl"/>
<bean id="userController" class="cn.edu.sicau.annotation.UserController"/>-->
<context:component-scan base-package="cn.edu.sicau.annotation"/>
</beans>
配置文件中注释的部分和<context:component-scan base-package=“cn.edu.sicau.annotation”/>起到同样的作用。
- 测试方法
@Test
public void func(){
ClassPathXmlApplicationContext applicationContext=new
ClassPathXmlApplicationContext("cn/edu/sicau/annotation/bean4.xml");
UserController userController = (UserController) applicationContext.getBean("userController");
userController.save();
}
自动装配
Spring 的元素中包含一个autowire属性,我们可以通过设置autowire 的属性值来自动装配Bean。所谓自动装配,就是将一个 Bean 自动地注入到其他 Bean的Property中。autowire属性有5个值,如下:
[外链图片转存失败(img-sQlDgBJD-1564703784765)(assets/spring-f2a9bd76.png)]
实例
- 修改上例中的UserServiceImpl和UserController,增加类属性的setter方法。
- 修改配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="userDao" class="cn.edu.sicau.annotation.UserDaoImpl"/>
<bean id="userService" class="cn.edu.sicau.annotation.UserServiceImpl" autowire="byName"/>
<bean id="userController" class="cn.edu.sicau.annotation.UserController" autowire="byName"/>
</beans>
Spring AOP
Spring简介
AOP采用横向抽取机制,将分散在各个方法中的重复代码抽取出来,在编译或运行时,再将这些代码应用到需要执行的地方。这里抽取出来的功能代码可以理解是一个个切面,如图:
[外链图片转存失败(img-7dtv2tIP-1564703784767)(assets/spring-6249cd84.png)]
AOP术语
- Aspect (切面):在实际应用中,切面通常是指封装的用于横向插入系统功能(如事务、日志等)的类。
- Joinpoint (连接点):在程序执行过程中的某个阶段点,它实际上是对象的一个操作,例
如方法的调用或异常的抛出 。 在 Spring AOP 中,连接点就是指方法的调用 - Pointcut (切入点):是指切面与程序流程的交叉点,即那些需要处理的连接点
- Advice( 通知/增强处理): AOP 框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码 。 可以将其理解为切面类中的方法。
- Target Object (目标对象):是指所有被通知的对象,也称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象。
- Proxy (代理):将通知应用到目标对象之后,被动态创建的对象 。
- Weaving (织入):将切面代码插入到目标对象上,从而生成代理对象的过程。
[外链图片转存失败(img-YFtx3lcg-1564703784769)(assets/spring-bc3a56e9.png)]
动态代理
AOP中的代理就是由AOP框架动态生成一个对象,该对象可以作为目标对象使用。Spring中的动态代理,可以是JDK动态代理,也可以是CGLIB代理。
JDK动态代理
JDK 动态代理是通过 java.lang. reflect. Proxy 类来实现的,我们可以调用 Proxy 类的newProxylnstanceO方法来创建代理对象。
实例
- 创建UserDao,添加增删方法
public interface UserDao {
void addUser();
void deleteUser();
}
- 创建实现类UserDaoImpl
public class UserDaoImpl implements UserDao{
@Override
public void addUser() {
System.out.println("增加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
- 创建切面类
public class MyAspect {
//前置增强方法
public void check_permission(){
System.out.println("检查权限");
}
//后置增强方法
public void log(){
System.out.println("打印日志");
}
}
- 创建代理类,需要实现InvocationHandler接口
public class JdkProxy implements InvocationHandler {
//申明目标接口类
private UserDao userDao;
public Object createProxy(UserDao userDao){
this.userDao=userDao;
//1. 类加载器
ClassLoader classLoader = JdkProxy.class.getClassLoader();
//2. 被代理对象实现的所有接口
Class[] clazz = userDao.getClass().getInterfaces();
//3. 使用代理类进行增强
return Proxy.newProxyInstance(classLoader,clazz,this);
}
/**
* 所有目标代理类的方法调用,都会交由invoke来处理
* @param proxy 被代理后的对象
* @param method 将要被执行的方法信息
* @param args 执行方法时需要的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//声明切面
MyAspect myAspect=new MyAspect();
//前置增强
myAspect.check_permission();
//在目标类上调用方法,并传入参数
Object invoke = method.invoke(userDao, args);
//后置增强
myAspect.log();
return invoke;
}
}
- 测试类
@Test
public void func(){
//创建代理对象
JdkProxy jdkProxy=new JdkProxy();
//创建目标对象
UserDao userDao=new UserDaoImpl();
//从代理对象中获取增强后的目标对象
userDao= (UserDao) jdkProxy.createProxy(userDao);
userDao.addUser();
userDao.deleteUser();
}
测试结果
[外链图片转存失败(img-j7DfO9Zq-1564703784772)(assets/spring-99a83983.png)]
CGLIB代理
和JDK动态代理比较,JDK动态代理有一定的局限性(动态代理的对象必须实现一个或多个接口),如果对没有实现接口的类进行代理,可以使用CGLIB代理。
实例
- 目标类 UserDao
public class UserDao {
public void addUser() {
System.out.println("增加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}
- 代理类
public class CGLibProxy implements MethodInterceptor {
//代理方法
public Object createProxy(Object target){
//创建动态增强类对象
Enhancer enhancer=new Enhancer();
//设置代理对象的父类
enhancer.setSuperclass(target.getClass());
//增加回调函数
enhancer.setCallback(this);
//返回创建的代理类
return enhancer.create();
}
/** proxy CGlib 根据指定父类生成的代理对象
* method 拦截的方法
* args 拦截方法的参数数组
* methodProxy 方法的代理对象,用于执行父类的方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
//创建界面对象
MyAspect myAspect=new MyAspect();
//前置增强
myAspect.check_permission();
//目标方法执行
Object invoke = methodProxy.invokeSuper(o, objects);
//后置增强
myAspect.log();
return invoke;
}
}
测试类省略
基于代理类的AOP实现
Spring通知类型
- org.aopalliance.intercept.MethodInterceptor (环绕通知)
在目标方法执行前后实施增强,可以应用于日志、事务管理等功能 。 - org.springframework.aop.MethodBeforeAdvice (前置通知)
在目标方法执行前实施增强,可以应用于权限管理等功能。 - org.springframework.aop.AfterReturningAdvice (后置通知)
在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。 - org.springframework.aop.ThrowsAdvice (异常通知)
在方法抛出异常后实施增强,可以应用于处理异常记录曰志等功能 。 - org.springframework.aop.IntroductionInterceptor (引介通知)
在目标类中添加一些新的方法和属性,可以应用于修改老版本程序(增强类)。
ProxyFactoryBean
ProxyFactoryBean是FactoryBean接口的实现类,FactoryBean负责实例化一个 Bean,而ProxyFactoryBean 负责为其他Bean创建代理实例。在Spring 中,使用ProxyFactoryBean是创建 AOP 代理的基本方式 。
ProxyFactoryBean常用可配置属性,如下图:
[外链图片转存失败(img-BU5QaX8p-1564703784774)(assets/spring-5a8bd2da.png)]
实例:环绕通知
在核心包的基础上再添加spring-aop-4.3.6.RELEASE.jar 和aopalliance-1.0.jar( http://mvnrepository.com/artifact/aopalliance/aopalliance/1.0" )
- 创建切面类MyAspect
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
check_permission();
//执行目标方法
Object proceed = methodInvocation.proceed();
log();
return proceed;
}
public void check_permission(){
System.out.println("检查权限");
}
public void log(){
System.out.println("打印日志");
}
}
- 配置文件
<?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-4.3.xsd">
<bean id="userDao" class="cn.edu.sicau.jdk.UserDaoImpl"/>
<bean id="myAspect" class="cn.edu.sicau.factory.MyAspect"/>
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--指定代理实现的接口-->
<property name="proxyInterfaces" value="cn.edu.sicau.jdk.UserDao"/>
<!--指定目标对象-->
<property name="target" ref="userDao"/>
<!--指定切面环绕通知-->
<property name="interceptorNames" value="myAspect"/>
<!--指定代理方式:true 对应cdlib\ false 默认jdk-->
<property name="proxyTargetClass" value="true"/>
</bean>
</beans>
- 测试类
@Test
public void func(){
String xmlPath="cn/edu/sicau/factory/applicationContext.xml";
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
UserDao userDaoProxy = (UserDao) applicationContext.getBean("userDaoProxy");
userDaoProxy.addUser();
userDaoProxy.deleteUser();
}
测试结果:
AspectJ开发
Spring的Java配置方式
Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:
- @Configuration 作用于类上,相当于一个xml配置文件;
- @Bean 作用于方法上,相当于xml配置中的;