欢迎光临
我们一直在努力

AspectJ 详解

AspectJ 是 Java 生态中最强大、最成熟的 AOP 框架,Spring AOP 的底层就依赖 AspectJ 的注解和切点表达式语法。

Spring AOP vs AspectJ

对比维度Spring AOPAspectJ
实现方式 动态代理(JDK/CGLIB) 字节码织入(编译期/类加载期/运行期)
织入时机 运行时 编译期、类加载期、运行期
性能 一般(代理调用开销) 更好(直接执行增强代码)
支持粒度 仅方法级别的连接点 字段、构造器、静态方法、异常处理等
目标对象限制 需要 Spring 容器管理 任意 Java 对象
private/protected 方法 ❌ 不支持 ✅ 支持(通过 Load-Time Weaving)
IDE 支持 一般 Eclipse/AJDT 插件支持

AspectJ 五种织入时机

织入类型时机说明
编译期织入 (CTW) 源代码编译时 需要 AspectJ 编译器(ajc)
编译后织入 (BTW) 编译后处理 class 文件 修改已有 class
加载期织入 (LTW) 类加载到 JVM 时 通过 Java Agent 实现,最灵活
运行时织入 运行时 Spring AOP 采用的方式(非原生 AspectJ)
混合织入 组合使用 部分代码编译期织入 + LTW

核心语法

1. 切点表达式完整语法

execution([权限修饰符] 返回值类型 [类全限定名.]方法名(参数列表) [throws 异常类型])

示例:

// 任意 public 方法
execution(public * *(..))

// 指定包下所有方法
execution(* com.example.service..*.*(..)) // .. 表示子包

// 参数匹配
execution(* *.*(String, int)) // 两个特定参数
execution(* *.*(..)) // 任意参数
execution(* *.*(String, ..)) // 第一个是 String,后面任意

// 返回值匹配
execution(* com.example.User+.*(..)) // User 及其子类的方法

2. 常用切点指示器
指示器说明示例
execution 匹配方法执行 execution(* com..*.*(..))
within 匹配类型内所有方法 within(com.example.service.*)
this 匹配代理对象类型 this(com.example.UserService)
target 匹配目标对象类型 target(com.example.UserService)
args 匹配参数类型 args(String, int)
@within 匹配有某注解的类型 @within(org.springframework.stereotype.Service)
@target 匹配目标对象有注解 @target(com.example.annotation.MyAnnotation)
@args 匹配参数有注解 @args(com.example.annotation.Valid)
@annotation 匹配方法有注解 @annotation(com.example.annotation.Log)
bean 匹配 Spring Bean 名称 bean(userService)

LTW(加载期织入)配置示例

1. 创建切面

@Aspect
public class PerformanceAspect {

@Around("execution(* com.example.service.*.*(..))")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
Object result = pjp.proceed();
long end = System.nanoTime();
System.out.println(pjp.getSignature() + " 耗时: " + (end – start) + "ns");
return result;
}

// 拦截字段访问
@Before("get(String com.example.User.name)")
public void beforeGetName() {
System.out.println("即将读取 name 字段");
}
}

2. META-INF/aop.xml

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose -showWeaveInfo">
<!– 指定需要织入的包 –>
<include within="com.example.service..*"/>
<include within="com.example.entity..*"/>
</weaver>

<aspects>
<aspect name="com.example.aspect.PerformanceAspect"/>
</aspects>
</aspectj>

3. JVM 启动参数

-javaagent:path/to/aspectjweaver.jar

Spring 集成 AspectJ

方式一:使用注解(最常用)

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 启用 AspectJ 注解支持
@ComponentScan("com.example")
public class AppConfig {
}

方式二:XML 配置

<aop:aspectj-autoproxy proxy-target-class="true"/>

<bean id="logAspect" class="com.example.aspect.LogAspect"/>

高级特性示例

1. 拦截字段赋值

@Aspect
public class FieldMonitorAspect {

@Before("set(* com.example.User.age)")
public void beforeSetAge(JoinPoint jp) {
int newAge = (int) jp.getArgs()[0];
if (newAge < 0 || newAge > 150) {
throw new IllegalArgumentException("年龄非法: " + newAge);
}
}
}

2. 拦截异常处理

@Aspect
public class ExceptionHandlerAspect {

@AfterThrowing(pointcut = "execution(* *.*(..))", throwing = "ex")
public void handleException(Exception ex) {
System.out.println("捕获异常: " + ex.getMessage());
// 自定义异常处理逻辑
}

// 拦截 Handler 方法本身
@Before("handler(java.lang.Exception+)")
public void beforeExceptionHandler() {
System.out.println("即将处理异常");
}
}

3. 多重切点组合

@Aspect
public class ComplexPointcutAspect {

// 定义复用切点
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

@Pointcut("@annotation(com.example.annotation.Auditable)")
public void auditableMethod() {}

@Pointcut("bean(*Service)")
public void serviceBean() {}

// 组合使用
@Before("serviceLayer() && auditableMethod() && !serviceBean()")
public void beforeCombined() {
System.out.println("满足多个条件的切点");
}
}

4. 软升级(Softening)异常

// 将受检异常转换为非受检异常
@DeclareSoft("execution(* *.*(..))")
public static SoftException softException;

性能优化建议

优化项说明
窄化切点 切点表达式越精确,匹配速度越快
避免使用 * 通配符过多 减少模式匹配开销
使用 within 替代 execution within 匹配更快(基于类型)
优先使用编译期织入 运行时开销最小
减少 AspectJ 切面数量 每个切面增加匹配检查
赞(0)
未经允许不得转载:171主机测评 » AspectJ 详解
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址