个人读书笔记,题外话都写在第1章https://blog.csdn.net/u013652550/article/details/119800308。
第4章介绍了AOP的主要概念,并列举了3种实现。
4.1 AOP基础
AOP的主要概念
横切关注点;切面;连接点;切入点;通知;目标对象;织入;引入。
4.2 AOP实现
1. 经典的基于代理的AOP
编写拦截器实现以下接口。
接口 | 方法 |
---|---|
AfterReturningAdvice | afterReturning(Object value, Method method, Object[] args, Object instance) |
MethodBeforeAdvice | before(Method method, Object[] args, Object instance) |
ThrowsAdvice | afterThrowing(Exception ex) |
ThrowsAdvice | afterThrowing(Method method, Object[] args, Object target, Exception ex) |
需引入spring-aop、spring-context。书上写的是在pom.xml中引入,实测还需要在XML配置文件中的beans内增加属性xmlns:aop,以及在对应的xsi:schemaLocation中补全。
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
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">
</beans>
安装时,先借助Spring中的代理类将自定义拦截器注入NameMatchMethodPointcutAdvisor类的advice属性中,再将定义好的NameMatchMethodPointcutAdvisor对象注入ProxyFactoryBean中。
<bean id="..." class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>...</value>
</list>
</property>
<property name="target" ref="..."/>
</bean>
2. AspectJ基于XML的配置
使用AspectJ时需要在pom.xml中引入两个依赖项,即aopalliance、aspectjweaver。
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>
(现在一般都使用注解,后面这张表以及XML配置可以跳了)
AOP配置元素 | 描述 |
---|---|
<aop:config> | 顶层的AOP配置元素,大多数的<aop:*>元素必须包含在<aop:config>元素内 |
<aop:aspect> | 定义切面 |
<aop:aspect-autoproxy> | 启用@AspectJ注解驱动的切面 |
<aop:pointcut> | 定义切点 |
<aop:advisor> | 定义AOP通知器 |
<aop:before> | 定义AOP前置通知 |
<aop:after> | 定义AOP后置通知(不管被通知的方法是否执行成功) |
<aop:after-returning> | 定义成功返回后的通知 |
<aop:after-throwing> | 定义抛出异常后的通知 |
<aop:around> | 定义AOP环绕通知 |
<aop:declare-parents> | 为被通知的对象引入额外的接口,并透明地实现 |
示例XML配置:
<aop:config>
<aop:aspect id="..." ref="...">
<aop:pointcut id="abc" expression="..."/>
<aop:before pointcut-ref="abc" method="..."/>
<aop:after pointcut-ref="abc" method="..."/>
<aop:after-returning pointcut-ref="abc" method="..." returning="..."/>
<aop:around pointcut-ref="abc" method="..."/>
<aop:after-throwing pointcut-ref="abc" method="..." throwing="e"/>
</aop:aspect>
</aop:config>
这里需要掌握一下execution表达式:Spring注解配置Aop - 乐之者v - 博客园 (cnblogs.com)
execution (* cn.itcast.service.impl.UserServiceImpl.*(..)):匹配UserServiceImpl类中声明的所有方法。第一个*代表任意修饰符及任意返回值类型,第二个*代表任意方法,..匹配任意数量任意类型的参数,若目标类与该切面在同一个包中,可以省略包名。
execution public * cn.itcast.service.impl.UserServiceImpl.*(..):匹配UserServiceImpl类中的所有公有方法。
execution public double cn.itcast.service.impl.UserServiceImpl.*(..):匹配UserServiceImpl类中返回值类型为double类型的所有公有方法。
execution public double cn.itcast.service.impl.UserServiceImpl.*(double, ..):匹配UserServiceImpl类中第一个参数为double类型,后面不管有无参数的所有公有方法,并且该方法的返回值类型为double类型。
execution public double cn.itcast.service.impl.UserServiceImpl.*(double, double):匹配UserServiceImpl类中参数类型为double,double类型的,并且返回值类型也为double类型的所有公有方法。
3. AspectJ基于注解的配置
使用@Aspect注解定义切面(放在类声明处)。以下为各注解示例用法。execution表达式内含义为省略,不可填写三点。
@Component
@Aspect
public class XXX {
@Before("execution(...)")
public void beforeAdvice() {...}
@After("execution(...)")
public void afterAdvice() {...}
@AfterReturning(value="execution(...)", returning="result")
public void afterReturnAdvice(String result) {...}
@Around("execution(...)")
public String aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {...}
@AfterThrowing(value="execution(...)", throwing="e")
public void throwingAdvice(JoinPoint joinPoint, Exception e) {...}
}
需要注意:环绕通知aroundAdvice方法体内需调用proceedingJoinPoint.proceed()以继续执行被拦截的方法。
关于异常方法中的joinPoint参数,一般调用joinPoint.getSignature()方法后进一步获取class等信息,具体可参考:JoinPoint的用法_斜阳雨陌-CSDN博客_joinpoint
最后注意在XML配置文件中使用<aop:aspect-autoproxy>开启即可。