如何用AspectJ在带自定义注解的类上触发方法与构造器前置切面?
非Spring项目下AspectJ实现注解切面的可行方案
问题根源分析
你当前的切面逻辑无效,核心问题是切点表达式匹配范围错误:
- 原表达式要求方法/构造器自身标注
@RunAdivceBeforeCall,但你的需求是类标注注解后,触发该类下所有方法、构造器的通知 - 未单独匹配构造器调用场景
- 非Spring环境下,无法依赖Spring的AOP自动代理,必须使用原生AspectJ的织入机制
修正后的代码实现
1. 修正自定义注解类
注意导入正确的Java注解包,原代码的import com.stackoverflow是错误的:
import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RunAdviceBeforeCall { // 注解无需额外属性,保留空即可 }
2. 编写正确的AspectJ切面类
调整切点表达式,覆盖类标注注解的所有实例方法、静态方法、构造器:
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class HandleAspect { // 匹配:类上标注@RunAdviceBeforeCall的所有实例方法和静态方法调用 @Before("execution(* (@RunAdviceBeforeCall *).*(..))") public void beforeMethodCall(JoinPoint joinPoint) { System.out.println("方法调用前触发通知:" + joinPoint.getSignature().getName()); // 你的业务逻辑 } // 匹配:类上标注@RunAdviceBeforeCall的构造器调用 @Before("execution(new(@RunAdviceBeforeCall *)(..))") public void beforeConstructorCall(JoinPoint joinPoint) { System.out.println("构造器调用前触发通知:" + joinPoint.getSignature().getName()); // 你的业务逻辑 } }
3. 目标类保持不变(确保类上标注注解)
@RunAdviceBeforeCall public class NavigationBar { public NavigationBar() { } public void navigateToHomePage() { } public void navigateToUserAccount() { } public void navigateToHelp() { } // 新增静态方法测试 public static void staticTestMethod() { } }
非Spring环境下的AspectJ织入配置
原生AspectJ需要手动配置织入,常用两种方式:
方式1:编译时织入(CTW)
通过Maven插件在编译阶段将切面代码织入目标类,适合打包前确定织入范围的场景:
- 在
pom.xml中添加AspectJ插件依赖:
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.14.0</version> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.9.1</version> </dependency> </dependencies> <configuration> <source>1.8</source> <!-- 匹配你的JDK版本 --> <target>1.8</target> <complianceLevel>1.8</complianceLevel> <aspectLibraries> <aspectLibrary> <groupId>你的项目groupId</groupId> <artifactId>你的项目artifactId</artifactId> </aspectLibrary> </aspectLibraries> </configuration> </plugin> </plugins> </build>
- 执行
mvn clean compile,插件会自动将切面织入目标类。
方式2:加载时织入(LTW)
在JVM加载类时动态织入切面,适合需要动态调整织入范围的场景:
- 引入AspectJ依赖:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.9.1</version> </dependency>
- 创建
META-INF/aop.xml配置文件,指定需要织入的切面和目标类:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver> <!-- 指定需要织入的包,*表示所有包 --> <include within="你的目标类包路径..*"/> </weaver> <aspects> <!-- 指定你的切面类 --> <aspect name="com.yourpackage.HandleAspect"/> </aspects> </aspectj>
- 启动JVM时添加JavaAgent参数:
java -javaagent:/path/to/aspectjweaver-1.9.9.1.jar -jar your-app.jar
内容的提问来源于stack exchange,提问作者gamelover
相关产品推荐
相关产品推荐

