- 是否有任何关于启用上述行为的体面示例,通常使用 AspectJ LTW 使用前两个选项来完成?
我的 GitHub 帐户上有几个 AspectJ 示例。这两个示例都展示了如何拦截同一目标对象内的调用(自调用)以及拦截私有方法。
- 使用 AspectJ 的 Spring Boot 源代码编织示例
- 使用 AspectJ 的 Spring Boot 加载时编织示例
这两个示例都相似,只是将方面编织到目标类中的方式不同。
请阅读示例的自述文件以了解有关每种编织类型以及如何使用每个示例的更多信息。
- 有没有办法选择性地启用 AspectJ LTW,例如,不是为 @Async 和 @Transactional 而只是 @Cacheable?
是的,您可以根据以下任一条件进行过滤:
通过调用者方法的注解类型。
@Before("call(* com.basaki.service.UselessService.sayHello(..))" +
" && cflow(@annotation(trx))")
public void inspectMethod(JoinPoint jp,
JoinPoint.EnclosingStaticPart esjp, Transactional trx) {
log.info(
"Entering FilterCallerAnnotationAspect.inspectMethod() in class "
+ jp.getSignature().getDeclaringTypeName()
+ " - method: " + jp.getSignature().getName());
}
通过调用方方法的名称。
@Before("call(* com.basaki.service.UselessService.sayHello(..))" +
" && cflow(execution(* com.basaki.service.BookService.read(..)))")
public void inspectMethod(JoinPoint jp,
JoinPoint.EnclosingStaticPart esjp) {
log.info(
"Entering FilterCallerMethodAspect.inspectMethod() in class "
+ jp.getSignature().getDeclaringTypeName()
+ " - method: " + jp.getSignature().getName());
}
您可以在此处找到工作示例。
更新
问:我是否理解正确,如果我想为事务性启用编译时编织,我会: 1. 不再在我的 DataSource 配置中的任何地方使用 TransactionAwareDataSourceProxy;2. 将以下内容添加到我的应用程序中:@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)。
Spring AOP 和 CTW/LTW AspectJ 编织是完全正交的,即它们彼此独立。
- compile和LTW修改实际的字节码,即将代码行插入到目标对象的方法体中。
- AOP是基于代理的,即目标对象有一个包装器。对目标对象的任何调用都会被 Spring 包装器对象拦截。如果需要,您还可以将 Spring AOP 与 CTW/LTW 一起使用。在这种情况下,Spring AOP 将对修改后的目标进行代理。
如果要@EnableTransactionManagement
启用 Spring 的注释驱动事务管理功能,则需要。
问:在您的示例中,我看到您没有为 CTW 以任何特殊方式启动应用程序。这足够了吗,还是我错过了什么?
是的,在 CTW 中,您在启动期间不需要任何特殊的东西,因为额外的字节码已经在编译ajc
期间由 AspectJ 编译器 ( ) 注入到原始代码中。例如,这里是原始源代码:
@CustomAnnotation(description = "Validates book request.")
private Book validateRequest(BookRequest request) {
log.info("Validating book request!");
Assert.notNull(request, "Book request cannot be empty!");
Assert.notNull(request.getTitle(), "Book title cannot be missing!");
Assert.notNull(request.getAuthor(), "Book author cannot be missing!");
Book entity = new Book();
entity.setTitle(request.getTitle());
entity.setAuthor(request.getAuthor());
return entity;
}
这是 AspectJ 编译器编译后的同一段代码ajc
:
private Book validateRequest(BookRequest request) {
JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, request);
CustomAnnotationAspect var10000 = CustomAnnotationAspect.aspectOf();
Annotation var10002 = ajc$anno$0;
if (ajc$anno$0 == null) {
var10002 = ajc$anno$0 = BookService.class.getDeclaredMethod("validateRequest", BookRequest.class).getAnnotation(CustomAnnotation.class);
}
var10000.inspectMethod(var3, (CustomAnnotation)var10002);
log.info("Validating book request!");
Assert.notNull(request, "Book request cannot be empty!");
Assert.notNull(request.getTitle(), "Book title cannot be missing!");
Assert.notNull(request.getAuthor(), "Book author cannot be missing!");
Book entity = new Book();
entity.setTitle(request.getTitle());
entity.setAuthor(request.getAuthor());
return entity;
}
在 LTW 中,您需要 Java 代理,因为代码在加载时被修改,即当类被 Java 类加载器加载时。