本文将讲解 FIT 框架中 AOP 的实现机制与调用链路,涉及 IoC 生命周期接入、拦截器解析与排序、切点匹配、代理创建与方法调用编排等核心组件。
主要涉及内容:
- 代码根目录:
framework/fit/java - 主要模块:
fit-aop/fit-aop(AOP 抽象与通用实现)、fit-aop/fit-aop-aspect(Aspect 切面实现)、fit-aop/fit-aop-bytebuddy(ByteBuddy 代理)、fit-api(公共 API)
1. AOP 何时介入:IoC 生命周期与 Bean 装饰
入口类:modelengine.fitframework.aop.AopInterceptor(实现 BeanLifecycleInterceptor)
关键位置:
isInterceptionRequired(BeanMetadata metadata):判定当前 Bean 是否需要 AOP 代理。源码使用所有MethodInterceptorResolver的eliminate(metadata)进行“短路淘汰”,当存在一个 resolver 认为该 bean 不应参与(返回 true),则整体不做 AOP;只有当所有 resolver 都不淘汰时才进入 AOP。decorate(BeanLifecycle lifecycle, Object bean):- 先调用下游生命周期装饰得到
initializedBean; - 聚合所有
MethodInterceptorResolver的结果,生成拦截器列表并按MethodInterceptorComparator排序; - 若非空,则构造
InterceptSupport; - 委派给
createAopProxy选择合适的AopProxyFactory创建代理;否则直接返回原对象。
- 先调用下游生命周期装饰得到
2. 拦截器模型与排序
核心接口:modelengine.fitframework.aop.interceptor.MethodInterceptor
MethodPointcut getPointCut():声明本拦截器适配的方法集合(运行前由匹配器筛选得到具体Method集合)。Object intercept(MethodJoinPoint jp):拦截器执行主体。
抽象基类:support.AbstractMethodInterceptor
- 内部维护
DefaultMethodPointcut,可在构造时注入若干MethodMatcher以约束匹配范围。
排序器:support.MethodInterceptorComparator
- 主序基于拦截器“种类”优先级:
Around > Before > After > AfterReturning > AfterThrowing。 - 次序通过
OrderResolver(SPI 可组合)解析@Order值;若解析失败取默认Order.MEDIUM。
相同连接点上的不同拦截器将按上述规则全局稳定排序,既保证 Advice 类型优先级,又支持业务自定义次序。
3. 切点与匹配:从“表达式”到“具体方法”
接口:MethodPointcut 与其默认实现 support.DefaultMethodPointcut
matchers():返回MethodMatcherCollection,用于收集一组MethodMatcher条件,所有 matcher 均通过时才认为方法匹配。add(Class<?>):为某个类收集“所有可匹配的方法”:- 先用每个 matcher 的
couldMatch(clazz)做类级短路; - 再遍历类、父类、接口上的
declaredMethods,逐个调用 matcher 的match(method); - 全部通过后,校验方法不能是
final或private,否则抛出异常; - 通知各 matcher 的
choose(method, result),最终把方法加入 pointcut。
- 先用每个 matcher 的
常用匹配器示例:
AccessibleMethodMatcher(MethodMatcher.accessible()工厂方法返回)AnnotationMethodMatcher(MethodMatcher.annotation(...))SpecifiedMethodMatcher(MethodMatcher.specified(method))
Aspect 风格的切点表达式解析位于 fit-aop-aspect 模块;解析产物最终都会体现在 MethodPointcut 的 methods() 具体集合上,供调用时过滤。
4. 拦截器解析(Resolver)与切面支持
入口:MethodInterceptorResolver
- 框架在
AopInterceptor中组装多个 resolver:- 内置:
AsyncInterceptorResolver、CacheInterceptorResolver - SPI 加载:
AspectInterceptorResolver等
- 内置:
resolve(BeanMetadata, bean)产出一组MethodInterceptor;eliminate(metadata)返回 true 则表示该 bean 不参与 AOP。
切面解析:fit-aop-aspect 模块
interceptor/aspect/interceptor/AspectInterceptorResolver- 收集当前容器中标注
@Aspect的BeanFactory,区分@Scope(PLUGIN)与@Scope(GLOBAL)两类来源(插件级与全局级)。 - 遍历切面方法,交给若干
MethodInterceptorFactory:AspectBefore/After/Around/AfterReturning/AfterThrowingInterceptorFactory- 工厂负责识别方法是否带对应注解、抽取切点表达式与参数绑定信息,创建具体的
AdviceMethodInterceptor实例(如AspectAfterInterceptor)。
- 收集当前容器中标注
eliminate(metadata):若当前 metadata 本身带@Aspect,返回 true,避免切面 bean 被 AOP。
Resolver 负责“把注解/表达式世界”转换成运行期可执行的 MethodInterceptor 列表,这是 AOP 生效的来源端。
5. 代理与调用链:如何把拦截器串起来
统一代理接口:fit-api 的 aop.proxy.FitProxy
Class<?> $fit$getActualClass():运行期可从代理对象取回被代理真实类型。
代理工厂聚合:aop.proxy.AopProxyFactories
- 通过 SPI 收集所有
AopProxyFactory并按@Order排序。
两种代理方式:
- JDK 动态代理:
support.JdkDynamicAopProxyFactorysupport(targetClass):当目标是接口、已是Proxy、或 Lambda 类时返回 true。createProxy(support):以公共子类加载器创建Proxy,接口数组为{ targetClass, FitProxy },回调为JdkDynamicProxy。
- ByteBuddy 子类代理:
fit-aop-bytebuddy/.../ByteBuddyAopProxyFactory- 对任意目标类型
support()返回 true(兜底方案) - 使用 ByteBuddy 生成
targetClass的子类,并implement(FitProxy),所有isMethod()由InvocationHandlerAdapter.of(new JdkDynamicProxy(support))统一接管。 - 使用
ReflectionFactoryInstantiator无参构造进行实例化,并以ConcurrentHashMap缓存已生成的代理类。
- 对任意目标类型
调用核心:support.AbstractAopProxy
- 关键方法:
protected Object invoke(Object proxy, Method method, Object[] args, ProxiedInvoker proxiedInvoker)- 拦截
$fit$getActualClass特殊方法:直接返回真实类型。 - 过滤出当前方法对应的拦截器列表:基于拦截器的
getPointCut().methods()包含关系 - 若为空:调用
proxiedInvoker.invoke(...)直接执行被代理对象(JDK 代理中由ReflectionUtils.invoke完成;ByteBuddy 通过InvocationHandlerAdapter转给同一个回调)。 - 若非空:构造责任链:
- 末尾追加
ProxiedInterceptor,其intercept(jp)通过proxiedInvoker最终调用被代理方法。 - 自尾向头包装
DefaultMethodJoinPoint与DefaultMethodInvocation,形成“嵌套的 nextInvocation”。 - 触发链路:调用第一个拦截器的
intercept(joinPoint)。
- 末尾追加
- 拦截
JDK 回调:support.JdkDynamicProxy(实现 InvocationHandler)
invoke(...)中调用父类AbstractAopProxy#invoke(...)。- 特殊处理
toString():当目标对象尚未初始化(懒加载 Supplier 还未返回)时,返回"$fit$" + targetClass + "#toString()"的占位字符串,避免空指针与递归问题。FitProxy.$fit$getActualClass()则在未初始化时返回null(见AbstractAopProxy#$fit$getActualClass)。
6. 关键约束与边界条件
- 目标方法不能是
final或private:DefaultMethodPointcut#validateMethod明确校验并抛错。 - 排序稳定性:先 Advice 类型优先级,再
@Order值;OrderResolver通过 SPI 组合,可扩展解析策略。 - 资源加载:拦截器解析器
MethodInterceptorResolver、OrderResolver、AopProxyFactory皆通过ServiceLoader扩展;确保相应模块提供META-INF/services声明。 - 类加载器:两种代理都使用
ClassLoaderUtils.getCommonChildClassLoader(...)获取公共子类加载器,确保代理类与FitProxy、目标类可见性一致。
7. 端到端调用链总览
- Bean 创建完成 →
AopInterceptor.decorate(...)- 聚合 Resolver → 产出并排序
List<MethodInterceptor>。 - 构造
DefaultInterceptSupport(targetClass, targetSupplier, interceptors)。 AopProxyFactories#getAll()选择第一个support(targetClass)的工厂创建代理(先 JDK,再 ByteBuddy,取决于@Order)。
- 聚合 Resolver → 产出并排序
- 方法被调用 → 进入
JdkDynamicProxy#invoke(...)或 ByteBuddy 生成类的InvocationHandlerAdapter,再委派到AbstractAopProxy#invoke(...)。 AbstractAopProxy#invoke(...):- 找到匹配当前
Method的拦截器子集;若空直接调用目标; - 子集尾部加
ProxiedInterceptor;自尾向头包裹MethodJoinPoint链; - 调用第一个拦截器的
intercept(joinPoint),在各拦截器内部按需joinPoint.proceed()继续推进,直至最终执行目标方法。
- 找到匹配当前
8. 最小可运行示例
示例结构:
// 1) 业务接口与实现
package demo;
public interface HelloService {
String hello(String name);
}
package demo;
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
return "hello, " + name;
}
}
// 2) 切面定义(Before 通知)
package demo;
import modelengine.fitframework.aop.annotation.Aspect;
import modelengine.fitframework.aop.annotation.Before;
import modelengine.fitframework.annotation.Scope;
@Aspect(scope = Scope.PLUGIN)
public class LogAspect {
@Before("execution(* demo.HelloService.hello(..))")
public void logBefore() {
System.out.println("[Before] about to call hello(..)");
}
}
输出
[Before] about to call hello(..)
hello, FIT