SpringAOP-AspectJ

AspectJ 与 Advisor 区别

Spring AOP和AspectJ虽然都支持@Aspect注解,但底层实现完全不同:

特性 Spring AOP AspectJ
实现方式 运行时动态代理 编译期/加载时字节码增强
拦截范围 仅Spring Bean的public方法 任意Java对象(包括构造器、字段等)
性能影响 有代理调用开销 无运行时损耗
依赖 Spring容器 需AspectJ编译器或织入器

Spring 集成 AspectJ 的两种方式

加载时织入(LTW)

配置步骤:添加 maven 依赖、启用 LTW(配置文件或JVM参数二选一)。不需要配置 maven 插件

  1. 添加依赖:
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
  1. 启用 LTW:

如果是 Spring 项目,没有配置文件,使用 @EnableLoadTimeWeaving 注解来开启

如果是 SpringBoot 项目可以配置文件开启,配置如下:

# application.properties
spring.aop.weaving=enable
  1. 或使用JVM参数:
-javaagent:/path/to/aspectjweaver.jar

编译时织入(CTW)

只需要配置 maven 插件就行了(不需要 JVM 参数、配置文件、maven 依赖)

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.14.0</version>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

AspectJ 示例

如果是想要前置、后置、环绕等通知,直接使用 SpringAOP(Advisor)

Advisor 和 AspectJ 可以共存,两者并不冲突

示例1:拦截对象构造

@Aspect // 没有 @Conponent 注解
public class ConstructionMonitorAspect {
    // 拦截所有ArrayList的构造
    @After("call(java.util.ArrayList.new(..))")
    public void afterArrayListCreation(JoinPoint jp) {
        System.out.println("ArrayList创建于: " + jp.getSourceLocation());
    }
}

示例2:字段访问监控

@Aspect // 没有 @Conponent 注解
public class FieldAccessAspect {
    // 拦截User对象的name字段读取
    @Before("get(* com.example.model.User.name)")
    public void beforeFieldRead(JoinPoint jp) {
        System.out.println("正在读取name字段");
    }
}

示例3:静态方法拦截

@Aspect // 没有 @Conponent 注解
public class StaticMethodAspect {
    // 拦截Math类的random方法调用
    @Around("call(public static double java.lang.Math.random())")
    public Object aroundRandomCall(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Math.random()被调用");
        return pjp.proceed();
    }
}
posted @ 2024-11-02 20:36  CyrusHuang  阅读(125)  评论(0)    收藏  举报