一、AOP基本概念
假设现在我们要对一个Test类进行事务代码织入,那么我们需要知道这个类有哪些方法,然后需要知道这个类的哪些方法需要织入事务代码。
1.目标类:需要织入日志代码的类,也就是Test类。
2.连接点:目标类的所有方法,都叫做连接点。
3.切点:切点就是具体织入日志代码的方法。
4.增强:织入的日志代码,就是增强部分。
5.织入:将增强和目标类的切点方法结合在一起,形成一个新的方法。
6.代理:持有织入后新的方法的类。
7.切面:包含切点的定义,连接点的定义,增强的定义。比如,日志切面,将Test类的add()方法定义为切点,日志代码定义为增强。性能监视切面,将Test类的add()方法定义为切点,性能监视代码定义为增强。
二、SpringBoot的简单实例
@Aspect
@Component
public class AspectJPOJO {
//在Springboot当中,直接定义一个切点就可以了,使用Component注解将切面纳入IOC容器管理,Spring会自动在调用目标类的时候,对切点进行拦截
@Before(value = "execution (* com.study.service.*.*(..))")
public void before(){
System.out.println("织入前");
}
}
使用SpringAOP的前提是,在项目中引入aspectjweaver包。上面的execution表示一个函数,第一个*表示返回值任意,第二个*表示service包下的任意类,第三个*表示任意方法,..表示参数为任意数量。Before注解的含义是在目标类的方法前添加增强。
三、不同增强类型
@Before:前置增强,织入在切点前面。
@AfterReturningAdvice:后置增强,织入在切点后面。可以使用returning属性将目标对象方法的返回值绑定给增强方法。如果目标方法抛异常,那么不会执行。
@AfterReturning(value = "execution (* com.study.service.*.*(..))",returning = "result")
public void afterReturning(Object result){
System.out.println("织入后" + result.toString());
}
@After:后置增强,织入在切点后面,无论目标方法是否抛异常,都会执行。
@After(value = "execution (* com.study.service.*.*(..))")
public void after(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName + "织入后");
}
@Around:环绕增强。一定要传入ProceedingJoinPoint类,调用joinPoint.proceed()方法相当于调用目标类的方法。
@Around(value = "logAnnotation()")
public void around(ProceedingJoinPoint joinPoint){
System.out.println("around前");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("around后");
}
@AfterThrowing:后置增强,将抛出的异常绑定到增强方法。
@AfterThrowing(value = "execution (* com.study.service.*.*(..))",throwing = "e")
public void afterThrowing(Exception e){
System.out.println(e.getMessage());
}
如@After后的代码所示,我们每个增强都可以传入一个JoinPoint类,通过该类可以获取切点的信息。
四、SpringAOP+自定义注解
注解类·
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
String value() default "!23";
}
切面方法
@Before(value = "@annotation(com.study.aspectj.LogAnnotation)")
public void beforeAnnotation(){
System.out.println("注解织入前");
}
因为@Before等等的增强方法后面配的都是切点,所以也可使用下面的配置方式
@Before(value = "logAnnotation()")
public void beforeAnnotationPointcut(){
System.out.println("注解切点织入前");
}
@Pointcut(value = "@annotation(com.study.aspectj.LogAnnotation)")
public void logAnnotation(){}
配置好之后只需要在业务逻辑上加上我们的自定义注解@LogAnnotation就可以了,SpringAOP会自动对纳入IOC容器的类里面的添加了@LogAnnotation注解的方法进行拦截,然后动态代理将代码织入到里面,默认使用JDK动态代理,如果不能使用JDK动态代理的情况,则会使用CGLib动态代理。
另外,如果针对不同的方法,我们进行不同的处理,需要获取自定义注解的信息,可以使用下面的代码
@Before(value = "logAnnotation()")
public void beforeAnnotationPointcut(JoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
System.out.println(annotation.value());
}
输出结果是我们的默认值,!23。