第五章:AOP 基础——五种增强方式详解
第五章:AOP 基础——五种增强方式详解
本章将深入探讨 Jfire 的 AOP(面向切面编程)实现,理解五种增强方式(@Before、@After、@Around、@AfterReturning、@AfterThrowable)的使用场景和工作原理,以及
EnhanceManager增强管理器的核心设计。
5.1 AOP 概念回顾
5.1.1 什么是 AOP
AOP(Aspect-Oriented Programming,面向切面编程) 是一种编程范式,它允许我们将横切关注点(如日志、事务、安全)从业务逻辑中分离出来。
传统编程中,这些横切关注点散布在各个业务方法中:
public class UserService {
public void createUser(User user) {
log.info("开始创建用户"); // 日志
checkPermission(); // 权限
beginTransaction(); // 事务开始
try {
userDao.save(user); // 业务逻辑
commitTransaction(); // 事务提交
log.info("用户创建成功"); // 日志
} catch (Exception e) {
rollbackTransaction(); // 事务回滚
log.error("用户创建失败", e); // 日志
throw e;
}
}
}
使用 AOP 后,业务代码变得简洁:
public class UserService {
@Transactional
public void createUser(User user) {
userDao.save(user); // 只关注业务逻辑
}
}
5.1.2 AOP 核心术语
| 术语 | 英文 | 说明 | Jfire 对应 |
|---|---|---|---|
| 切面 | Aspect | 横切关注点的模块化 | @EnhanceClass 标注的类 |
| 连接点 | Join Point | 程序执行的某个点 | ProceedPoint |
| 切入点 | Pointcut | 匹配连接点的规则 | @Before("save*") 中的规则 |
| 通知/增强 | Advice | 在切入点执行的动作 | @Before、@After 等 |
| 织入 | Weaving | 将切面应用到目标对象 | 字节码生成 |
5.1.3 Jfire 的 AOP 特点
- 编译时织入:通过字节码生成技术,在容器启动时创建增强类
- 五种增强方式:完整支持前置、后置、环绕、返回后、异常后增强
- 灵活的切入点:支持方法名通配符和自定义匹配器
- 链式执行:多个增强器按顺序执行
5.2 EnhanceManager 增强管理器架构
EnhanceManager 是 AOP 的核心接口,定义了增强管理器的行为:
// 源码:cc/jfire/jfire/core/aop/EnhanceManager.java
public interface EnhanceManager {
// 计数器:用于生成唯一的字段/类/方法名
AtomicInteger FIELD_NAME_COUNTER = new AtomicInteger(0);
AtomicInteger CLASS_NAME_COUNTER = new AtomicInteger(0);
AtomicInteger METHOD_NAME_COUNTER = new AtomicInteger(0);
AtomicInteger VAR_NAME_COUNTER = new AtomicInteger(0);
// 预定义的 order 值
int DEFAULT = 100; // 普通 AOP
int TRANSACTION = 10; // 事务
int CACHE = 30; // 缓存
int VALIDATE = 50; // 验证
/**
* 扫描并标记需要增强的 Bean
*/
default void scan(ApplicationContext context) {
context.getAllBeanRegisterInfos().stream()
.filter(needEnhance(context))
.forEach(info -> info.addEnhanceManager(EnhanceManager.this));
}
/**
* 判断是否需要增强的谓词
*/
Predicate<BeanRegisterInfo> needEnhance(ApplicationContext context);
/**
* 执行增强操作
* @param classModel 增强类的类模型
* @param type 被增强的原始类
* @param context 应用上下文
* @param hostFieldName 原始实例的字段名
*/
void enhance(ClassModel classModel, Class<?> type,
ApplicationContext context, String hostFieldName);
/**
* 增强器的执行顺序(数值越小越先执行)
*/
int order();
}
5.2.1 内置增强管理器
Jfire 内置了三个增强管理器:
| 增强管理器 | order | 职责 |
|---|---|---|
| TransactionEnhanceManager | 10 | 声明式事务管理 |
| CacheEnhanceManager | 30 | 声明式缓存 |
| AopEnhanceManager | 100 | 普通 AOP(五种增强方式) |
5.2.2 执行顺序的重要性
增强器的 order() 决定了执行顺序:
请求到达
│
▼
┌───────────────────────────────────────┐
│ TransactionEnhanceManager (order=10) │ ← 最先执行(事务开始)
└───────────────┬───────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ CacheEnhanceManager (order=30) │ ← 缓存检查
└───────────────┬───────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ AopEnhanceManager (order=100) │ ← 普通 AOP
└───────────────┬───────────────────────┘
│
▼
目标方法执行
│
▼
逆序返回
为什么事务管理器 order 最小?
事务需要包裹所有其他操作,最先开始、最后结束。
5.3 @EnhanceClass:定义切面类
@EnhanceClass 注解用于标记一个类是切面类:
// 源码:cc/jfire/jfire/core/aop/notated/EnhanceClass.java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Resource // 自动注册为 Bean
public @interface EnhanceClass {
/**
* 匹配目标类的表达式
* 支持通配符:* 匹配任意字符
*/
String value() default "";
/**
* AOP 执行的顺序。数字越大的越先执行,越先执行的越晚结束
*/
int order() default 0;
}
5.3.1 类匹配规则
value 属性支持通配符匹配:
| 表达式 | 匹配说明 | 示例 |
|---|---|---|
com.example.service.* |
匹配 service 包下的所有类 | UserService、OrderService |
com.example.*.impl.* |
匹配任意子包下的 impl 包 | dao.impl.UserDaoImpl |
*Service |
匹配以 Service 结尾的类 | 任何 XxxService |
com.example.UserService |
精确匹配 | 只匹配 UserService |
5.3.2 使用示例
// 定义切面类
@EnhanceClass("com.example.service.*") // 匹配 service 包下的所有类
public class LoggingAspect {
@Before("save*(*)") // 匹配所有 save 开头的方法
public void beforeSave(ProceedPoint point) {
System.out.println("准备保存: " + Arrays.toString(point.getParams()));
}
@After("*(*)") // 匹配所有方法
public void afterAll(ProceedPoint point) {
System.out.println("方法执行完成: " + point.getMethod().methodName());
}
}
5.4 ProceedPoint:连接点抽象
ProceedPoint 是对方法执行点的抽象,它提供了获取方法信息和控制执行的能力:
// 源码:cc/jfire/jfire/core/aop/ProceedPoint.java
public interface ProceedPoint {
/**
* 调用目标方法(仅在环绕增强中有效)
*/
void invoke();
/**
* 获取目标对象实例
*/
Object getHost();
/**
* 获取被拦截方法的描述信息
*/
MethodDescription getMethod();
/**
* 获取异常(仅在异常增强中有效)
*/
Throwable getE();
/**
* 获取方法返回值(仅在返回后增强和环绕增强中有效)
*/
Object getResult();
/**
* 设置返回值(仅在环绕增强中有效)
*/
void setResult(Object result);
/**
* 获取方法参数数组
*/
Object[] getParams();
// 方法描述内部类
class MethodDescription {
final String methodName;
Class<?>[] paramTypes;
public String methodName() { return methodName; }
public Class<?>[] getParamTypes() { return paramTypes; }
}
}
5.4.1 ProceedPointImpl 实现
// 源码:cc/jfire/jfire/core/aop/ProceedPointImpl.java
public class ProceedPointImpl implements ProceedPoint {
protected Object host; // 目标对象
protected Object result; // 返回结果
protected Throwable e; // 异常
protected Object[] params; // 参数数组
protected MethodDescription methodDescription; // 方法描述
@Override
public void invoke() {
result = invokeInternel(); // 调用内部方法
}
// 环绕增强时会被重写的方法
public Object invokeInternel() {
throw new RuntimeException("该方法只在环绕增强方法中可被调用");
}
// getter/setter 方法...
}
5.4.2 ProceedPoint 在各增强中的可用方法
| 方法 | @Before | @After | @Around | @AfterReturning | @AfterThrowable |
|---|---|---|---|---|---|
getHost() |
✅ | ✅ | ✅ | ✅ | ✅ |
getMethod() |
✅ | ✅ | ✅ | ✅ | ✅ |
getParams() |
✅ | ✅ | ✅ | ✅ | ✅ |
invoke() |
❌ | ❌ | ✅ | ❌ | ❌ |
getResult() |
❌ | ❌ | ✅ | ✅ | ❌ |
setResult() |
❌ | ❌ | ✅ | ❌ | ❌ |
getE() |
❌ | ❌ | ❌ | ❌ | ✅ |
5.5 五种增强方式详解
5.5.1 @Before:前置增强
执行时机:目标方法执行前
// 源码:cc/jfire/jfire/core/aop/notated/Before.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {
String value() default ""; // 方法匹配规则
Class<? extends MatchTargetMethod> custom() default MatchTargetMethod.class;
}
使用示例:
@EnhanceClass("com.example.service.*")
public class ValidationAspect {
@Before("create*(*)") // 匹配所有 create 开头且有参数的方法
public void validateParams(ProceedPoint point) {
Object[] params = point.getParams();
for (Object param : params) {
if (param == null) {
throw new IllegalArgumentException("参数不能为空");
}
}
System.out.println("参数验证通过");
}
@Before("delete*(int)") // 匹配 delete 开头且参数为 int 的方法
public void checkDeletePermission(ProceedPoint point) {
// 检查删除权限
System.out.println("检查删除权限,ID: " + point.getParams()[0]);
}
}
生成的代码结构:
// 原始方法
public void createUser(User user) {
// 原始逻辑
}
// 增强后的方法
public void createUser(User user) {
// 【前置增强代码】
ProceedPointImpl point = new ProceedPointImpl();
point.setHost(host);
point.setParams(new Object[]{user});
point.setMethodDescription(new MethodDescription("createUser", ...));
validationAspect.validateParams(point);
// 【原始逻辑】
// 原始代码...
}
5.5.2 @After:后置增强
执行时机:目标方法执行后(无论是否异常)
// 源码:cc/jfire/jfire/core/aop/notated/After.java
@Retention(RUNTIME)
@Target(METHOD)
public @interface After {
String value() default "";
Class<? extends MatchTargetMethod> custom() default MatchTargetMethod.class;
}
使用示例:
@EnhanceClass("com.example.service.*")
public class ResourceCleanupAspect {
@After("process*(*)") // 所有 process 开头的方法
public void cleanup(ProceedPoint point) {
System.out.println("清理资源: " + point.getMethod().methodName());
}
}
生成的代码结构:
// 增强后的方法
public void processData(Data data) {
try {
// 【原始逻辑】
// 原始代码...
} finally {
// 【后置增强代码】
ProceedPointImpl point = new ProceedPointImpl();
// 设置 point 属性...
resourceCleanupAspect.cleanup(point);
}
}
特点:使用 try-finally 结构,确保无论是否异常都会执行。
5.5.3 @Around:环绕增强
执行时机:完全控制目标方法的执行
// 源码:cc/jfire/jfire/core/aop/notated/Around.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Around {
String value() default "";
Class<? extends MatchTargetMethod> custom() default MatchTargetMethod.class;
}
使用示例:
@EnhanceClass("com.example.service.*")
public class PerformanceAspect {
@Around("*(*)") // 所有方法
public void measureTime(ProceedPoint point) {
long start = System.currentTimeMillis();
try {
point.invoke(); // 调用目标方法
} finally {
long duration = System.currentTimeMillis() - start;
System.out.println(point.getMethod().methodName()
+ " 执行耗时: " + duration + "ms");
}
}
@Around("query*(*)")
public void cacheResult(ProceedPoint point) {
String cacheKey = generateCacheKey(point);
Object cached = cache.get(cacheKey);
if (cached != null) {
point.setResult(cached); // 直接设置结果,不调用目标方法
return;
}
point.invoke(); // 调用目标方法
cache.put(cacheKey, point.getResult()); // 缓存结果
}
}
生成的代码结构:
// 增强后的方法
public User getUser(int id) {
final int $0 = id; // 参数声明为 final
ProceedPointImpl point = new ProceedPointImpl() {
public Object invokeInternel() {
// 【原始逻辑】
return host.getUser($0);
}
};
// 设置 point 属性...
performanceAspect.measureTime(point);
return (User) point.getResult();
}
关键点:
- 原始方法体被移入匿名内部类的
invokeInternel()方法 - 参数被声明为
final(匿名内部类访问需要) - 通过
point.invoke()调用原始方法 - 可以不调用
invoke(),直接设置结果
5.5.4 @AfterReturning:返回后增强
执行时机:目标方法正常返回后(无异常)
// 源码:cc/jfire/jfire/core/aop/notated/AfterReturning.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterReturning {
String value() default "";
Class<? extends MatchTargetMethod> custom() default MatchTargetMethod.class;
}
使用示例:
@EnhanceClass("com.example.service.*")
public class AuditAspect {
@AfterReturning("create*(*)")
public void auditCreation(ProceedPoint point) {
Object result = point.getResult();
System.out.println("创建成功,结果: " + result);
auditLog.log("CREATE", point.getMethod().methodName(), result);
}
@AfterReturning("update*(*)")
public void auditUpdate(ProceedPoint point) {
System.out.println("更新成功: " + point.getMethod().methodName());
}
}
生成的代码结构:
// 原始方法被重命名
private User createUser_0(User user) {
// 原始逻辑
return newUser;
}
// 新生成的方法
public User createUser(User user) {
User result = createUser_0(user); // 调用原始方法
ProceedPointImpl point = new ProceedPointImpl();
// 设置 point 属性...
point.setResult(result); // 设置返回值
auditAspect.auditCreation(point);
return result;
}
与 @After 的区别:
| 特性 | @After | @AfterReturning |
|---|---|---|
| 执行时机 | 无论成功失败都执行 | 只在成功返回时执行 |
| 获取返回值 | ❌ | ✅ point.getResult() |
| 异常时执行 | ✅ | ❌ |
5.5.5 @AfterThrowable:异常后增强
执行时机:目标方法抛出异常后
// 源码:cc/jfire/jfire/core/aop/notated/AfterThrowable.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterThrowable {
String value() default "";
Class<? extends MatchTargetMethod> custom() default MatchTargetMethod.class;
}
使用示例:
@EnhanceClass("com.example.service.*")
public class ExceptionHandlerAspect {
@AfterThrowable("*(*)") // 所有方法
public void handleException(ProceedPoint point) {
Throwable e = point.getE();
String method = point.getMethod().methodName();
// 记录异常日志
logger.error("方法 {} 执行异常", method, e);
// 发送告警
alertService.sendAlert("方法异常: " + method, e.getMessage());
}
}
生成的代码结构:
// 增强后的方法
public void doSomething() {
try {
// 【原始逻辑】
// 原始代码...
} catch (Throwable e) {
ProceedPointImpl point = new ProceedPointImpl();
// 设置 point 属性...
point.setE(e); // 设置异常
exceptionHandlerAspect.handleException(point);
ReflectUtil.throwException(e); // 重新抛出异常
return; // 编译需要的占位代码
}
}
注意:异常增强不会吞掉异常,执行完增强逻辑后会重新抛出。
5.6 方法匹配规则
5.6.1 MatchTargetMethod 接口
// 源码:cc/jfire/jfire/core/aop/notated/support/MatchTargetMethod.java
public interface MatchTargetMethod {
boolean match(Method method);
}
5.6.2 默认实现:NameMatch
NameMatch 是默认的方法匹配器,支持方法名和参数类型的通配符匹配:
// 源码:cc/jfire/jfire/core/aop/notated/support/impl/NameMatch.java
public class NameMatch implements MatchTargetMethod {
private final String rule;
public NameMatch(String rule) {
this.rule = rule;
}
@Override
public boolean match(Method method) {
// 1. 解析方法名规则
String methodNameRule = rule.substring(0, rule.indexOf('('));
if (!StringUtil.match(method.getName(), methodNameRule)) {
return false;
}
// 2. 解析参数规则
String paramRule = rule.substring(rule.indexOf('(') + 1, rule.length() - 1);
// (*) 匹配任意参数
if ("*".equals(paramRule)) {
return true;
}
// () 匹配无参方法
if ("".equals(paramRule)) {
return method.getParameterTypes().length == 0;
}
// 逐个匹配参数类型
String[] split = paramRule.split(",");
Class<?>[] parameterTypes = method.getParameterTypes();
if (split.length != parameterTypes.length) {
return false;
}
for (int i = 0; i < split.length; i++) {
String literals = split[i].trim();
if ("*".equals(literals)) {
continue; // * 匹配任意类型
}
// 匹配简单类名或全限定名
if (!literals.equals(parameterTypes[i].getSimpleName())
&& !literals.equals(parameterTypes[i].getName())) {
return false;
}
}
return true;
}
}
5.6.3 匹配规则语法
| 规则 | 说明 | 匹配示例 |
|---|---|---|
save(*) |
save 方法,任意参数 | save(User)、save(int, String) |
save() |
save 方法,无参 | save() |
save*(*) |
save 开头的方法,任意参数 | save、saveUser、saveAll |
*User(*) |
以 User 结尾的方法 | getUser、createUser |
get(int) |
get 方法,参数为 int | get(int) |
update(*, String) |
update 方法,两个参数,第二个是 String | update(int, String) |
find(User, *) |
find 方法,第一个参数是 User | find(User, int) |
5.6.4 自定义匹配器
// 自定义匹配器:只匹配有特定注解的方法
public class AnnotationMatch implements MatchTargetMethod {
@Override
public boolean match(Method method) {
return method.isAnnotationPresent(NeedLog.class);
}
}
// 使用自定义匹配器
@EnhanceClass("com.example.*")
public class CustomAspect {
@Before(custom = AnnotationMatch.class) // 使用自定义匹配器
public void beforeAnnotatedMethod(ProceedPoint point) {
// 只有标注 @NeedLog 的方法才会被增强
}
}
5.7 AopEnhanceManager 源码解析
让我们深入分析 AopEnhanceManager 的实现:
5.7.1 needEnhance:判断是否需要增强
// 源码:AopEnhanceManager.java
@Override
public Predicate<BeanRegisterInfo> needEnhance(ApplicationContext context) {
if (list == null) {
list = new LinkedList<>();
// 1. 收集所有切面类信息
context.getAllBeanRegisterInfos().stream()
.filter(info -> AnnotationContext.isAnnotationPresent(
EnhanceClass.class, info.getType()))
.map(info -> info.getType())
.forEach(ckass -> {
// 获取 @EnhanceClass 的 value 值列表
List<String> enhanceClass = Stream.iterate(ckass,
c -> c != Object.class, c -> c.getSuperclass())
.filter(c -> AnnotationContext.isAnnotationPresent(
EnhanceClass.class, c))
.map(c -> AnnotationContext.getAnnotation(
EnhanceClass.class, c).value())
.toList();
// 收集所有增强方法的匹配器
Set<MatchTargetMethod> collect = /* ... */;
list.add(new EnhanceClassData(enhanceClass, collect));
});
}
// 2. 返回判断谓词
return beanRegisterInfo -> list.stream()
// 检查类名是否匹配
.filter(v -> v.enhanceClass.stream().anyMatch(
each -> StringUtil.match(beanRegisterInfo.getType().getName(), each)))
// 检查是否有匹配的方法
.flatMap(v -> v.collection().stream())
.anyMatch(matchTargetMethod -> Arrays.stream(
beanRegisterInfo.getType().getDeclaredMethods())
.anyMatch(matchTargetMethod::match));
}
5.7.2 enhance:执行增强
// 源码:AopEnhanceManager.java
@Override
public void enhance(ClassModel classModel, final Class<?> originType,
ApplicationContext applicationContext, String hostFieldName) {
MethodModel setEnhanceFieldsMethod = getSetEnhanceFieldsMethod(classModel);
// 查找适用于当前类的切面
List<BeanRegisterInfo> aspectList = findAspectClass(originType, applicationContext);
for (BeanRegisterInfo aspect : aspectList) {
String fieldName = "enhance_" + FIELD_NAME_COUNTER.getAndIncrement();
int sum = 0;
// 按顺序处理五种增强(顺序很重要!)
sum += processBeforeAdvice(/* ... */); // 1. 前置增强
sum += processAroundAdvice(/* ... */); // 2. 环绕增强
sum += processAfterAdvice(/* ... */); // 3. 后置增强
sum += processAfterReturningAdvice(/* ... */); // 4. 返回后增强
sum += processAfterThrowableAdvice(/* ... */); // 5. 异常后增强
// 如果有增强,添加切面字段
if (sum > 0) {
addFiledAndBuildSet(classModel, setEnhanceFieldsMethod, aspect, fieldName);
}
}
}
5.7.3 处理前置增强示例
// 源码:AopEnhanceManager.java
private boolean processBeforeAdvice(ClassModel classModel, Class<?> originType,
AnnotationContext annotationContextOnEnhanceMethod,
String hostFieldName, String fieldName, Method enhanceMethod) {
Before before = annotationContextOnEnhanceMethod.getAnnotation(Before.class);
MatchTargetMethod matchTargetMethod = getMatchTargetMethod(
enhanceMethod, before.value(), before.custom());
return Arrays.stream(originType.getDeclaredMethods())
.filter(method -> !method.isBridge())
.filter(method -> !Modifier.isStatic(method.getModifiers()))
.filter(method -> matchTargetMethod.match(method))
.peek(method -> {
logger.debug("前置通知规则匹配成功,方法:{},通知方法:{}",
method.getDeclaringClass().getSimpleName() + "." + method.getName(),
enhanceMethod.getDeclaringClass().getSimpleName() + "." + enhanceMethod.getName());
// 获取现有方法模型
MethodModel.MethodModelKey key = new MethodModel.MethodModelKey(method);
MethodModel methodModel = classModel.getMethodModel(key);
String originBody = methodModel.getBody();
// 生成前置增强代码
String pointName = "point_" + FIELD_NAME_COUNTER.getAndIncrement();
StringBuilder cache = new StringBuilder();
if (enhanceMethod.getParameterTypes().length == 0) {
// 无参增强方法,直接调用
cache.append(fieldName).append(".").append(enhanceMethod.getName())
.append("();\r\n");
} else {
// 有参增强方法,需要创建 ProceedPoint
generateProceedPointImpl(classModel, hostFieldName, method,
pointName, cache, false);
generateEnhanceMethodInvoke(fieldName, enhanceMethod, pointName, cache);
}
// 前置代码 + 原始代码
cache.append(originBody);
methodModel.setBody(cache.toString());
}).count() > 0;
}
5.8 增强执行顺序
当多个增强作用于同一方法时,执行顺序如下:
┌─────────────────────────────────────────────────────────────┐
│ 方法调用 │
└─────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ @Before (前置增强) │
│ 按 aspect order 顺序执行 │
└─────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ @Around (环绕增强开始) │
│ point.invoke() 调用前的代码 │
└─────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 目标方法执行 │
└─────────────────────────┬───────────────────────────────────┘
│
┌──────┴──────┐
│ │
正常返回 抛出异常
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ @AfterReturning │ │ @AfterThrowable │
│ (返回后增强) │ │ (异常后增强) │
└────────┬────────┘ └────────┬────────┘
│ │
└──────────┬───────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ @Around (环绕增强结束) │
│ point.invoke() 调用后的代码 │
└─────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ @After (后置增强) │
│ 在 finally 块中执行 │
└─────────────────────────┬───────────────────────────────────┘
│
▼
返回结果
5.9 完整示例
5.9.1 业务服务
@Resource
public class UserService {
@Resource
private UserDao userDao;
public User createUser(String name, int age) {
User user = new User(name, age);
userDao.save(user);
return user;
}
public User getUser(int id) {
return userDao.findById(id);
}
public void deleteUser(int id) {
userDao.delete(id);
}
}
5.9.2 切面类
@EnhanceClass("com.example.service.*")
public class ComprehensiveAspect {
// 1. 前置增强:参数验证
@Before("create*(*, int)")
public void validateAge(ProceedPoint point) {
int age = (int) point.getParams()[1];
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄不合法: " + age);
}
System.out.println("【前置】年龄验证通过: " + age);
}
// 2. 后置增强:资源清理
@After("*(*)")
public void logCompletion(ProceedPoint point) {
System.out.println("【后置】方法执行完成: " + point.getMethod().methodName());
}
// 3. 环绕增强:性能监控
@Around("get*(*)")
public void measurePerformance(ProceedPoint point) {
long start = System.nanoTime();
try {
point.invoke();
} finally {
long duration = System.nanoTime() - start;
System.out.println("【环绕】" + point.getMethod().methodName()
+ " 耗时: " + duration / 1_000_000.0 + "ms");
}
}
// 4. 返回后增强:审计日志
@AfterReturning("create*(*)")
public void auditCreation(ProceedPoint point) {
Object result = point.getResult();
System.out.println("【返回后】创建成功: " + result);
}
// 5. 异常后增强:异常处理
@AfterThrowable("delete*(*)")
public void handleDeleteError(ProceedPoint point) {
Throwable e = point.getE();
System.out.println("【异常后】删除失败: " + e.getMessage());
}
}
5.9.3 运行结果
// 调用 createUser("张三", 25)
【前置】年龄验证通过: 25
【返回后】创建成功: User{name='张三', age=25}
【后置】方法执行完成: createUser
// 调用 getUser(1)
【环绕】getUser 耗时: 0.5ms
【后置】方法执行完成: getUser
// 调用 deleteUser(999) - 假设抛出异常
【异常后】删除失败: 用户不存在
【后置】方法执行完成: deleteUser
Exception: 用户不存在
5.10 本章小结
本章我们深入学习了 Jfire 的 AOP 实现:
-
EnhanceManager 架构
- 定义了增强管理器的核心接口
- 通过
order()控制执行顺序 - 内置三个增强管理器:事务、缓存、AOP
-
五种增强方式
@Before:前置增强,方法执行前@After:后置增强,方法执行后(finally)@Around:环绕增强,完全控制执行@AfterReturning:返回后增强,正常返回时@AfterThrowable:异常后增强,抛出异常时
-
ProceedPoint 连接点
- 提供方法信息、参数、返回值、异常的访问
- 环绕增强中可调用
invoke()执行原方法
-
方法匹配规则
- 支持方法名通配符:
save*、*User - 支持参数匹配:
(*),(),(int, String) - 支持自定义匹配器
- 支持方法名通配符:
-
代码生成
- 前置:增强代码 + 原始代码
- 后置:try { 原始 } finally { 增强 }
- 环绕:匿名内部类包装原始方法
- 返回后:调用原始 → 设置 result → 调用增强
- 异常后:try { 原始 } catch { 增强; rethrow }
下一章预告:我们将深入 AOP 的字节码生成实现,了解 Jfire 如何使用 SMC 库动态创建增强类,以及增强类的完整结构。
思考题
-
为什么
@Around增强需要将参数声明为final? -
如果同一个方法被多个切面的同类型增强(如多个 @Before)匹配,执行顺序是怎样的?
-
@After和@AfterReturning能否同时作用于一个方法?它们的执行顺序是什么? -
如何实现一个自定义的
EnhanceManager,比如参数验证增强器?
核心源码清单
| 文件 | 路径 | 核心内容 |
|---|---|---|
| EnhanceManager.java | core/aop/ | 增强管理器接口 |
| AopEnhanceManager.java | core/aop/impl/ | AOP 增强管理器实现 |
| ProceedPoint.java | core/aop/ | 连接点接口 |
| ProceedPointImpl.java | core/aop/ | 连接点实现 |
| EnhanceClass.java | core/aop/notated/ | 切面类注解 |
| Before.java | core/aop/notated/ | 前置增强注解 |
| After.java | core/aop/notated/ | 后置增强注解 |
| Around.java | core/aop/notated/ | 环绕增强注解 |
| AfterReturning.java | core/aop/notated/ | 返回后增强注解 |
| AfterThrowable.java | core/aop/notated/ | 异常后增强注解 |
| MatchTargetMethod.java | core/aop/notated/support/ | 方法匹配器接口 |
| NameMatch.java | core/aop/notated/support/impl/ | 默认方法匹配器 |
专栏以轻量级 Java 框架 Jfire 为蓝本,带你从零手写一个完整的 IOC 容器。专栏共 10 章,涵盖 IOC 容器核心原理:Bean 定义与生命周期、Bean 工厂设计、五种依赖注入策略、循环依赖解决方案;深入 AOP 实现:五种增强方式、字节码动态生成技术;以及企业级特性:声明式事务管理(四种传播级别)、声明式缓存框架、条件注解与自动配置机制。
查看14道真题和解析