与基于代理类的AOP实现相比,基于XML的声明式ApectJ要便捷得多,但是它也存在着一些缺点,那就是要在Spring文件中配置大量的代码信息。为了解决这个问题,AspectJ框架为AOP实现提供了一套注解,用以取代Spring配置文件中为实现AOP功能所配置的臃肿代码。
以下为关于AspectJ注解的介绍:
@Aspect:用于定义一个切面。
@Pointcut:用于定义切入点表达式。在使用时还需定义一个包含名字和任意参数的方法签名来表示切入点名称。实际上,这个方法签名就是一个返回值为void,且方法体为空的普通的方法。
@Before:用于定义前置通知,相当于BeforeAdvice。在使用时,通常需要指定一个value属性值,该属性值用于指定一个切入点表达式(可以是已有的切入点,也可以直接定义切入点表达式)。
@AfterReturning:用于定义后置通知,相当于AfterReturningAdvice。在使用时可以指定pointcut/value和returning属性,其中pointcut/value 这两个属性的作用一样,都用于指定切入点表达式。returning属性值用于表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法的返回值。
@Around:用于定义环绕通知,相当于MethodInterceptor。在使用时需要指定一个 value属性,该属性用于指定该通知被植入的切入点。
@AfterThrowing:用于定义异常通知来处理程序中未处理的异常,相当于ThrowAdvice。在使用时可指定pointcut/value和throwing属性。其中pointcut/value用于指定切入点表达式,而throwing属性值用于指定一个形参名来表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法抛出的异常。
@After:用于定义最终final通知,不管是否异常,该通知都会执行。使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点。
@DeclareParents:用于定义引介通知,相当于IntroductionInterceptor (不要求掌握)
为了快速理解掌握这些注解,接下来用注解的形式来实现代码展示:
package com.nowcoder.community.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AlphaAspect {
// 定义切入点表达式
@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
// 使用一个返回返回值为void、方法体为空的方法来命名切入点
public void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void before() {
System.out.println("before");
}
// 最终通知
@After("pointcut()")
public void after() {
System.out.println("after");
}
// 后置通知
@AfterReturning("pointcut()")
public void afterRetuning() {
System.out.println("afterRetuning");
}
// 异常通知
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("afterThrowing");
}
// 环绕通知
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before");
Object obj = joinPoint.proceed();
System.out.println("around after");
return obj;
}
}
在代码中,首先使用@Aspect注解定义了切面类,由于该类在Spring中是作为组件使用的,所以还需要添加@Component注解才能生效。然后使用了@Pointcut注解来配置切入点表达式,并通过定义方法来表示切入点名称。接下来在每个通知相应的方法上添加了相应的注解,并将切入点名称“pointcut"作为参数传递给需要执行增强的通知方法。如果需要其他参数(如异常通知的异常参数),可以根据代码提示传递相应的属性值。
相对来说,使用注解的方式更加简单、方便,所以在实际开发中推荐使用注解的方式进行AOP开发。