AspectJ作为语言级别的AOP框架,功能相比于SpringAOP更加强大。SpringAOP旨在提供给用户一个轻量级的AOP实现方案,它只能应用在SpringIOC容器中管理的bean。而AspectJ旨在提供给用户一个完整的AOP解决方案,它可以应用在所有的域对象中。
AspectJ在织入代码时,有三种不同类型的编织:
官网对于织入时机的解释
SpringAOP是基于动态代理来实现的,在运行期通过接口或者子类的方式来实现AOP。在SpringAOP中主要有两种:
本文主要介绍AspectJ在SpringBoot中的两种实现(CTW、LTW)
使用CTW的方式织入时,需要采用特殊的编译器(ajc)来进行编译
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver> <include within="com.zakary.qingblog..*" /> </weaver> <aspects> <aspect name="com.zakary.qingblog.aop.LoginAspect"/> <aspect name="com.zakary.qingblog.aop.InterceptorAspect"/> <aspect name="com.zakary.qingblog.aop.ParamsCheckAspect"/> </aspects> </aspectj>
@Aspect @DeclarePrecedence("InterceptorAspect,LoginAspect,ParamsCheckAspect") public class LoginAspect { private Logger logger= LoggerFactory.getLogger(QingblogApplication.class); /** * 匹配规则 * execution: 用于匹配方法执行的连接点; * execution(public * *(..)) ==> 匹配所有目标类的public方法,第一个*代表返回类型,第二个*代表方法名,而..代表任意入参的方法。 * execution(* com.oysept.springboot.controller..*.*(..)) ==> 该包及所有子包下任何类的任何方法。 * execution(* com.oysept.springboot.controller.*(..)) ==> 该包下任何类的任何方法。 * execution(* com.oysept.springboot.controller.AspectJController.*(..)) ==> 该包下AspectJController类的任何方法。 * execution(* com..*.*Controller.method*(..)) ==> 匹配包名前缀为com的任何包下类名后缀为Controller的方法,方法名必须以method为前缀。 * execution(* *To(..)) ==> 匹配目标类所有以To为后缀的方法。 * 注: 该方法只是为了声明一个公共的环绕通知,也可以直接在具体方法配置,如: @Around("execution(* com.oysept.springboot.controller..*.*(..))") */ @Pointcut("execution(* com.zakary.qingblog.controller.LoginController.userLogin(..))") public void loginAop() {} @Before("loginAop()") public void before(JoinPoint point) throws Throwable { Object[] objArgs = point.getArgs(); String mail= AnalysisUtils.getObjectToMap(objArgs[0]).get("userMail").toString(); String password=AnalysisUtils.getObjectToMap(objArgs[0]).get("userPassword").toString(); logger.info("User Login : [ userMail : "+mail+"\t , password : "+password+"\t ]"); } }
切入点
@Controller public class LoginController { @Autowired private LoginService loginService; @RequestMapping("/userLogin") @ResponseBody public JSONResult userLogin(@RequestBody @Validated({ValidationGroups.LoginGroup.class}) User user, HttpServletRequest request){ User user1=loginService.login(user); HttpSession session=request.getSession(); session.setAttribute("userId",user1.getUserId()); return JSONResult.ok("success"); } }
编译后的class文件
@Controller public class LoginController { @Autowired private LoginService loginService; public LoginController() { } @RequestMapping({"/userLogin"}) @ResponseBody public JSONResult userLogin(@RequestBody @Validated({LoginGroup.class}) User user, HttpServletRequest request) { JoinPoint var5 = Factory.makeJP(ajc$tjp_0, this, this, user, request); JSONResult var9; try { LoggerAspect.aspectOf().before(var5); LoginAspect.aspectOf().before(var5); ParamsCheckAspect.aspectOf().beforeLogin(var5); User user1 = this.loginService.login(user); HttpSession session = request.getSession(); session.setAttribute("userId", user1.getUserId()); var9 = JSONResult.ok("success"); } catch (Throwable var10) { LoggerAspect.aspectOf().releaseResource(var5); throw var10; } LoggerAspect.aspectOf().releaseResource(var5); return var9; } static { ajc$preClinit(); } }
图中执行了多个AspectOf方法,因为我在此处实现了多个切面
spring: aop: auto: false
关闭Springaop
设置ltw CustomLtwConfig.java
@Configuration @ComponentScan("com.zakary.qingblog.controller") @EnableLoadTimeWeaving(aspectjWeaving=ENABLED) public class CustomLtwConfig{ }
注:aspectjWeaving有三个值,ENABLED为强制使用LTW的方式,DISENABLED不使用,AUTODETECT为查找META-INF下有无aop.xml文件,如果没有,不使用LTW,有的话使用LTW
@DeclarePrecedence("InterceptorAspect,LoginAspect,ParamsCheckAspect")
参考文章
CTW
LTW