一、简介
Spring Aop的注解是在IOC注解基础上,重点突出增强类(Advice)的注解,一个增强类可以看成是一个切面(Aspect),因此,Aop注解的学习,基本上可以是看成增强类所用到的注解的学习。重点需要掌握了解以下几个知识点:
- 增强类定义为组件Bean的同时,还需要定义为增强类(切面)的Bean,因此,他需要在@Componen的基础上,再加上注解@Aspec;
- 增强类中的增强方法上,可以用注解来定义这个增强方法可以用在哪些切入点上;
- 切入点可以映射到一个方法中,这个方法可以是Advice(增强类)中的一个方法,也可以自定义类中定义的一个静态方法,如果切入点还要引入到别的增强类,那么建议使用自定义类的静态方法做为切入点的引用;
- 由于目标对象(被代理对象)以及增强类都被加载到AOP容器中,且这个Bean和Aspect都存在注解对这两个Bean的说明,因此,在xml文件中,产生代理对象只需一句代码;
二、增强类(Advice)加载到AOP文件中
Advice是一个增强类,加载到AOP容器的时候,需要配置两个注解。一是他作为一个正常的Bean的注解@Component,另一个是作为一个切面(Advice)@Aspect,具体示例代码如下:
import aop3.pos.StringToUserPropertiesEditor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserAop5Advice {
// TODO: 2021/6/30 将增强类中的增强方法做为代理对象方法的前置增强 ,切入点的定义是在一个类中,用静态方法引入了切入点
@Before(value = "UserAspect.aspect()")
public void beforeAdvice(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String methodSignatureName = methodSignature.getName();
Object[] args = joinPoint.getArgs();
Object target = joinPoint.getTarget();
System.out.println("beforeAdvice:" + methodSignatureName + ";Args:" + args + ";Target:" + target);
}
// TODO: 2021/7/1 这个方法只能适用于切入点的后置,是一个增强类的后置增强方法,需要与注解或者xml命名空间来配合使用
@AfterReturning(value = "UserAspect.aspect2()",returning = "object")
public void afterAdvice(JoinPoint joinPoint,Object object){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String methodSignatureName = methodSignature.getName();
Object[] args = joinPoint.getArgs();
Object target = joinPoint.getTarget();
System.out.println("afterAdvice: methonName:" + methodSignatureName + ";Args:" + args + "; Target:" + target + ";retunValue:" + object);
}
// TODO: 2021/7/1 这个增强类方法是环绕增强,以调用目标对象的方法调用为分界线,之前是前置,之后是后置
@Around(value = "UserAspect.aspect2()")
public Object beforeAndAfterAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("开启事务处理");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("结束事务处理");
return proceed;
}
// TODO: 2021/7/1 增强类中的异常处理增强,这是由参数决定的,方法名是可以随意取的,他必须和注解或者命名空间配合使用
@AfterThrowing(value = "UserAspect.aspect2()",throwing = "exception")
public void exceptionAdvice(JoinPoint joinPoint,Exception exception){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String methodSignatureName = methodSignature.getName();
Object[] args = joinPoint.getArgs();
Object target = joinPoint.getTarget();
System.out.println("ExceptionAdvice: methonName:" + methodSignatureName + ";Args:" + args + "; Target:" + target + ";exception:" + exception);
}
}
三、增强类的增强方法切入点及在切入点位置的定义
指的是,增强类中的增强方法可用于哪些切入点。在知道切入点的时候,还需要明确增强方法在切入点的位置是前置、后置、环绕还是异常,因此,在定义增强方法中的切入点注解是与切入点位置是相对应的,也就是说,增强类中增强方法所用的注解包含两层的意思:
- 明确增强方法可用于哪些切入点
- 明确增强方法在切入点的具体位置(前置、后置、环绕和异常)
以下表格所表示注解为增强类中增强方法的注解
增强注解 | 说明 |
---|---|
@Before(切点方法()) | 前置增强 |
@AfterReturning | 后置增强 |
@Around | 环绕增强 |
@AfterThrowing | 异常增强 |
- 切入点方法的映射
可以用一个方法映射到切和点,这个方法可以增强类(Advice)中的一个方法,也可以自定义类中一个静态方法,其核心还是在方法上用一个@Pointcut(切点表达式)注解,参数中的切点表达式是Aspect表达式,主要有两个方法:within()方法和execution()方法
// TODO: 2021/6/30 这是一个自定义类,自定义类中的静态方法映射到一个切入点
public class UserAspect {
@Pointcut(value = "execution(* aop5.impl.*.*(..))")
public static void aspect(){}
}
在增强类的增强方法上明确增强注解,说明该增强方法所能织入的切入点,及在切入点上的位置(前置、后置、环绕、异常)
四、在xml文件中,动态创建代理对象
在SpringAOP容器中,通过包扫描已将目标对象(被代理对象)和增强类实例(Aspect)在AOP容器中进行生成,所以需要通过一个后置处理器以这个目标对象为结构,动态的创建一个代理类实例,在xml简化的配置可以使用一行代友来实现:
<!-- TODO:自动成生代理代,采取的仍然是后置处理器,通过getBean()方法获得代理类实例所用的ID仍然是:目标对象用注解定义的ID -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
五、理解后置处理器是如何动态创建代理类
在xml中,通过aop:aspectj-autoproxy,可以在AOP容器中自加载一个后置处理器,通过这个后置处理器,调用指定的动态代理创建技术(JDK技术和CGLIB技术)JDK技术适用于接口实现类,而CGLIB技术更适用于非接口实现类(变通类)