您现在的位置是:首页 >学无止境 >Spring Advice是如何转换为MethodInterceptor网站首页学无止境
Spring Advice是如何转换为MethodInterceptor
前文我们探讨了AOP中几个重要的概率,Advice作为通知抽象的标记接口,有多种实现类,在最终织入到Joinpoint中后都会转换为MethodInterceptor形成拦截器链,以便于统一调用invoke方法,那么这个过程是如何做到的呢?我们接下来就详细分析其过程。
Advice的多种子接口
五种Advice具体实现,他们都继承了抽象的AbstractAspectJAdvice
从名称上不难猜测这几个具体实现分别对应解析@Aspect
注解配置类中的@Before
,@After
,@AfterReturning
,@AfterThrowing
,@Around
五种类型的通知注解。
Advice转换为MethodInterceptor的适配器
AdvisorAdapter是用来将封装在Advisor中的具体Advice通知,根据其具体通知类型转换为MethodInterceptor,因为只有这三种类型需要转换,故只有三种实现(AroundAdvice实际上已经实现了MethodInterceptor不用转换)。我们具体看看是如何转换的:
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
// 利用AfterReturningAdviceInterceptor对通知进行封装
return new AfterReturningAdviceInterceptor(advice);
}
}
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
// 继续执行拦截器链或目标方法
Object retVal = mi.proceed();
// 返回后调用通知方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
所以这里必然对应着三种静态代理类
具体在何时被转换的呢?
我们根据猜测已经看到了类结构图,猜想了其具体实现原理,那么在什么时候被转换为拦截器链的呢?猜想两个时机可能被创建,要么在创建代理对象,要么在方法执行的时候去封装。
- 在创建代理对象后方法不一定会被调用执行,那么这会损耗性能,同时我们知道所有的代理对象都可以转换为
Advised
,并可以调用Advised#advice()
方法继续添加通知(未冻结)。 - 从这个角度出发,不难猜测真正创建拦截器链必然是在方法的执行时才会创建,并且不会缓存(若缓存了那么新加的通知就不会生效),如果缓存必须在修改通知时清除缓存。
我们以jdk动态代理为例,分析JdkDynamicAopProxy,它实现了InvocationHandler,在invoke方法中肯定有如何创建拦截器链的方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// ... 省略部分代码....
Object retVal;
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 创建拦截器链(通过Advised配置)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// ...省略部分代码...
return retVal;
}
}
果然符合猜测结果,是在方法执行时才创建的拦截器链,那么继续确认是否有缓存存在呢?
// 在Advised的抽象实现AdvisedSupport中
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 获取拦截器链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
他娘的,居然有缓存,那么说明在添加通知方法(Advised#addAdvice())的时候必然会清除缓存,否则导致新增通知无效。
private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
Assert.notNull(advisor, "Advisor must not be null");
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
}
if (pos > this.advisors.size()) {
throw new IllegalArgumentException("Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
this.advisors.add(pos, advisor);
adviceChanged();
}
// 清除缓存
protected void adviceChanged() {
this.methodCache.clear();
}
果然是在添加通知的时候有回调清除方法对应的拦截器缓存,这里印证了猜想。
同时,在上面创建拦截器方法我们看到是使用工厂类DefaultAdvisorChainFactory
的方式来创建的拦截器链,接下来继续分析到底是如何创建拦截器链,也就是如何从Advice转换为了MethodInterceptor
DefaultAdvisorChainFactory拦截器链创建工厂
该类是AdvisorChainFactory接口的唯一实现,封装了如何从Advised配置中将Advisor中的Advice转换为拦截器。
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 全局适配器注册中心(注册了上面说道的三个转换适配器AdvisorAdaptor)
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 取出配置中的Advisor
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
// 分类型处理
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 类是否满足等
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
// 方法是否满足切点表达式
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
} else {
// 方法是否满足切点表达式
match = mm.matches(method, actualClass);
}
if (match) {
// 使用适配器进行转换
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
// 添加到拦截器链中
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
} else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
// 匹配成功后并转化为MethodInterceptor,最后添加到拦截器链中
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
} else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
/**
* Determine whether the Advisors contain matching introductions.
*/
private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
for (Advisor advisor : advisors) {
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(actualClass)) {
return true;
}
}
}
return false;
}
}
这里运用到AdvisorAdapterRegistry全局适配器注册中心,我们继续看看注册的适配器
适配器注册中心AdvisorAdapterRegistry
前面我们说了三类通知的适配器如何将Advice转换为MethodInterceptor,这里就是这些适配器的用武之地。
public final class GlobalAdvisorAdapterRegistry {
private GlobalAdvisorAdapterRegistry() {
}
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
public static AdvisorAdapterRegistry getInstance() {
return instance;
}
}
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
// 注册了上文所说的适配器
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
// 转换为MethodInterceptor
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 本身实现了MethodInterceptor,如@Around,@After
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 对于注册的三种Advice
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
为什么只注册了三种AdvisorAdapter适配器
我们在前面讨论了共有五种通知类型,除了@Around
还有@Before
,@After
,@AfterReturning
,@AfterThrowing
四种,这里为什么只有三种适配器呢,我们看看@After
其也实现了MethodInterceptor,这里只有三种适配器。
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
} finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
至此,整个链路就串联起来了,从Advice到MethodInterceptor,spring通过层层封装,配置等方式,将多种通知类型最用运用到代理对象上,结合动态代理使代理对象得到通知增强。