第3章 Spring AOP
3.1.1 什么是AOP
AOP的全称是Aspect Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式
AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充
目前最流行的AOP框架有两个,分别为Spring AOP 和 AspectJ
Spring AOP:使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理的方式向目标类织入增强的代码
AspectJ:是一个基于Java语言的AOP框架,从Spring2.0开始,Spring AOP引入对AspectJ的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码织入
3.1.2 AOP术语
切面(Aspect):共有功能的实现,如日志切面,权限切面等,在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别称切面,是在配置文件中指定的
连接点(Joinpoint):在程序的执行过程中的某个阶段点,它实际上是对象的一个操作,例如方法的调用或异常的抛出。在Spring AOP中,连接点就是指方法的调用
切入点(Pointcut):是指切面与程序的交叉点,即哪些需要处理的连接点,通常在程序中,切入点指的是类或者方法名,如某个通知要应用到所有以add开头的方法中,那么所有满足这以规则的方法都是切入点
通知/增强处理(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的
目标对象(Target Object):是指所有被通知的对象,也称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理的对象
代理(Proxy):将通知应用到目标对象之后,被动态创建的对象
织入(Weaving):将切面代码插入到目标对象上,从而生成代理对象的过程
3.2 动态代理
JDK动态代理:是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
CGLIB(Code Generation Library):是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强
动态代理推荐文章:
(1)https://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html
(2)https://www.cnblogs.com/xiaocao123/p/10686424.html
3.3 基于代理类的AOP实现
Spring中的AOP代理默认就是使用JDK动态代理的方式实现的,使用ProxyFactoryBean是创建AOP代理的最基本方式
3.3.1 Spring的通知类型
Spring中的通知按照在目标类方法的连接点位置,可以分为以下5种类型:
1.环绕通知(org.aopalliance.intercept.MethodInterceptor):在目标方法执行前后实施增强,可以应用于日志,事务管理等功能
2.前置通知(org.springframework.aop.MethodBeforeAdvice):在目标方法执行前实施增强,可以应用于权限管理等功能
3.后置通知(org.springframework.aop.AfterReturningAdvice):在目标方法执行后实施增强,可以应用于关闭流,上传文件,删除临时文件等功能
4.异常通知(org.springframework.aop.ThrowsAdvice):在方法抛出后实施增强,可以应用于处理异常记录日记等功能
5.引介通知(org.springframework.aop.IntroductionInterceptor):在目标类种添加一些新的方法和属性,可以应用于修改老版本程序(增强类)
Spring的通知类型推荐文章:https://www.cnblogs.com/chuijingjing/p/9806651.html
3.3.2 ProxyFactoryBean
ProxyFactoryBean:是FactoryBean接口的实现类,FactoryBean负责实例化一个Bean,而ProxyFactoryBean负责为其他Bean创建代理实例。在Spring中,使用ProxyFactoryBean是创建AOP代理的基本方式
ProxyFactoryBean类中的常用可配置属性如下:
| 属性名称 | 描述 |
|---|---|
| target | 代理的目标对象 |
| proxyinterfaces | 代理要实现的接口 |
| proxyTargetClass | 是否对类代理而不是接口,设置为true时,使用CGLIB代理 |
| interceptorNames | 需要织入目标的Advice |
| singleton | 返回的代理是否为单实例,默认为true(即返回单实例) |
| optimize | 当设置为true时,强制使用CGLIB |
3.4 AspectJ开发
AspectJ开发推荐文章:https://www.cnblogs.com/chy18883701161/p/11144207.html
3.4.1 基于XML的声明式AspectJ
基于XML的声明式AspectJ:是指通过XML文件来定义切面,切入点及通知,所有的切面,切入点和通知都必须定义在aop:config元素内
1.配置切面
在Spring的配置文件中,配置切面使用的是aop:aspect元素,该元素会将一个已定义好的Spring Bean转换成切面Bean,所以要在配置文件中先定义一个普通的Spring Bean。定义完成后,通过aop:aspect元素的ref属性即可引用该Bean
配置aop:aspect元素时,通常会指定id和ref两个属性
| 属性名称 | 描述 |
|---|---|
| id | 用于定义该切面的唯一标识名称 |
| ref | 用于引用普通的Spring Bean |
2.配置切入点
在Spring的配置文件中,切入点是通过aop:pointcut元素来定义的。当aop:pointcut元素作为aop:config元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所共享;当aop:pointcut元素作为aop:aspect元素的子元素时,表示该切入点只对当前切面有效
配置aop:pointcut元素时,通常会指定id和expression两个属性
| 属性名称 | 描述 |
|---|---|
| id | 用于指定切入点的唯一标识名称 |
| expression | 用于指定切入点关联的切入点表达式 |
Spring AOP中切入点表达式的基本格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
1.modifiers-pattern:表示定义目标方法的访问修饰符
2.ret-type-pattern:表示定义的目标方法的返回值类型
3.declaring-type-pattern:表示定义的目标方法的类路径
4.name-pattern:表示具体需要被代理的目标方法
5.param-pattern:表示需要被代理的目标方法包含的参数
6.throws-pattern:表示需要被代理的目标方法抛出的异常类型
其中带有问好(?)的部分,表示可配项;而其他部分属于必须配置项
3.配置通知
在配置代码中,分别使用aop:aspect的子元素配置了5种常用通知,这5个子元素不支持使用子元素,但在使用时可以指定一些属性,如下表
| 属性名称 | 描述 |
|---|---|
| pointcut | 该属性用于指定一个切入点表达式,Spring将在匹配该表达式的连接点时织入该通知 |
| pointcut-ref | 该属性指定一个已经存在的切入点名称,如配置代码中的myPointCut。通常pointcut和pointcut-ref两个属性只需要使用其中之一 |
| method | 该属性指定一个方法名,指定将切面Bean中的该方法转换为增强处理 |
| throwing | 该属性只对<after-throwing>元素有效,它用于指定一个形参名,异常通知方法可以通过该形参访问目标方法所抛出的异常 |
| returning | 该属性只对<after-returning>元素有效,它用于指定一个形参名,后置通知方法可以通过该形参访问目标方法的返回值 |
注意:后置通知只有在目标方法成功执行后才会被织入,而最终通知不论目标方法如何结束(包括成功执行和异常中止两种情况),它都会被织入
3.4.2 基于注解的声明式AspectJ
AspectJ框架为AOP的实现提供了一套注解,用以取代Spring配置文件中为实现AOP功能所配置的臃肿代码
| 注解名称 | 描述 |
|---|---|
| @Aspect | 用于定义一个切面 |
| @Pointcut | 用于定义切入点表达式。在使用时还需定义一个包含名字和任意参数的方法签名来表示切入点名称,实际上,这个签没就是一个返回值为void,且方法体为空的普通方法 |
| @Before | 用于定义前置通知,相当于BeforeAdvice。在使用时,通常需要指定一个value属性值,该属性值用于指定一个切入点表达式(可以是已有的切入点,也可以直接定义切入点表达式) |
| @AfterReturning | 用于定义后置通知,相当于AfterReturningAdvice。在使用时可以指定pointcut/value和returning属性,其中pointcut/value这两个属性的作用一样,都用于指定切入点表达式。returning属性值用于表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法的返回值 |
| @Around | 用于定义环绕通知,相当于Methodlnterceptor。在使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点 |
| @AfterThrowing | 用于定义异常通知来处理程序中未处理的异常,相当于ThrowAdvice。在使用时可指定pointcut/value和throwing属性。其中pointcut/value用于指定切入点表达式,而throwing属性值用于指定一个形参名来表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法抛出的异常 |
| @After | 用于定义最终final通知,不管是否异常,该通知都会执行。使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点 |
| @DeclareParents | 用于定义引介通知,相当于introductionlnterceptor |
注意:如果在同一个连接点有多个通知需要执行,那么在同一个切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的,目标方法之后的后置通知和环绕通知的执行顺序也是未知的
在Spring中使用AspectJ实现AOP推荐文章:https://www.cnblogs.com/chy18883701161/p/11144903.html
本文深入探讨了Spring AOP和AspectJ,介绍了AOP的基本概念,如切面、连接点和通知类型。讲解了动态代理,包括JDK动态代理和CGLIB,并展示了如何使用ProxyFactoryBean创建AOP代理。此外,文章还详细阐述了基于XML和注解的声明式AspectJ配置,帮助读者掌握AOP在Java EE中的应用。
1874

被折叠的 条评论
为什么被折叠?



