Spring AOP的核心是动态代理,那么动态代理核心是什么呢?
动态代理有两个核心:1可以动态的生成代理对象;2在回调方法invoke中,我们做的一些额外的操作,这个也是可以是动态。
即动态的生成代理对象以及动态的执行额外的操作。
代码:
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
doBefore();
method.invoke(target, args);
doAfter() ;
return null;
}
Dobefore 和doafter的具体实现时未定的,所以这个地方可以写接口方法,具体是实现根据具体情况而确定,这有点类似于模板设计模式,具体是实现有子类来完成。
在上一篇博客中我们已经分析了SpringAOP生成动态代理对象的过程。Spring Aop中定义的通知就是我们动态执行的额外操作。
我们这一节就是分析这些通知是什么时候执行的。
在web编程中,我们都使用过拦截器,其实拦截器就是一种面向切面编程的表现方式。在spring Aop中,通知的执行,最终是转为拦截器执行的。所以在配置中我们使用interceptName来配置通知,这个单词还是用的拦截器的英文单词。
这一节涉及到类比较多,尽量将清楚。
先看动态代理的invoke方法,我们假设此方法所在的类为:
JdkDynamicAopProxy我们主要看这两行:
1、取得通知器链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
2、通知器链不为空 进行后面的执行
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain.
Object retVal = invocation.proceed();
一、取得通知器链
This.advised 这个就是AdvisedSupport ,这个类是的实例是在生成JdkDynamicAopProxy对象传过来的。并且AdvisedSupport 里面存有通知器链。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;
}
我们看这个取得通知器链的方法,里面还使用了缓存。 这个取得通知器链的过程又使用了变量advisorChainFactory,
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
那现在就要去看这个通知器链工厂了DefaultAdvisorChainFactory
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
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)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
现在先总结一下,就是在invoke方法被触发调用之后,会先获取通知器链,这个通知器链由AdvisedSupport持有,又需要通过默认的通知器链工厂生成。
我们继续看通知器链工厂里面做了哪些事情:
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
通知器注册类
这个通知器注册类实际上是:
static void reset() {
instance = new DefaultAdvisorAdapterRegistry();
}
DefaultAdvisorAdapterRegistry
这个通知器注册类的作用是根据通知器,返回拦截器数组。
我们看源码方法:
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) 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[interceptors.size()]);
}
核心的一句:
interceptors.add(adapter.getInterceptor(advisor));
就是添加一个通知器。
具体一点:我们是要将通知器添加进拦截器数组。
我们需要一个适配,需要将通知器适配为拦截器。
通知器适配器就应运而生了:AdvisorAdapter
我们看下这个通知器适配器,他是一个接口:
AdvisorAdapter
boolean supportsAdvice(Advice advice);
取得对应通知器的方法拦截器
MethodInterceptor getInterceptor(Advisor advisor);
他正好有一个抽象方法将通知器转为拦截器。
他有三个实现:
MethodBeforeAdviceAdapter
AfterReturningAdviceAdapter
ThrowsAdviceAdapter
看下第一个:MethodBeforeAdviceAdapter
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
获取通知器中的通知,将通知 适配为对应拦截器
因此这个时候,三个对应拦截器也诞生了:
MethodBeforeAdviceInterceptor
AfterReturningAdviceInterceptor
ThrowsAdviceInterceptor
我们先看下他们公共接口:MethodInterceptor:
他有一个回调方法:
Object invoke(MethodInvocation invocation) throws Throwable;
我们继续看一个实现:MethodBeforeAdviceInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
也就是当这个invoke被触发调用时,先执行通知的会调用方法,这个是前置通知,所以先执行before方法。然后再执行MethodInvocation 的proceed方法。
现在总结一下,就是通知器链工厂,在生成通知器链的时候,先将advice适配为对应拦截器,然后存放到list中。我们现在的问题是那个拦截器中的invoke什么调用。不过现在我们已经获得了拦截器链。
获得了拦截器链,还需要得到一个Advice的MethodMatcher,然后这拦截器和MethodMatcher一同封装到这个类中:
InterceptorAndDynamicMethodMatcher
类的实现一目了然:
class InterceptorAndDynamicMethodMatcher {
final MethodInterceptor interceptor;
final MethodMatcher methodMatcher;
public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
this.interceptor = interceptor;
this.methodMatcher = methodMatcher;
}
}
我们将这个类存放到List interceptorList
最终返回。
所以通知器链工厂最终返回的通知器链是包含通知器和methodMatcher的。
二、、通知器链不为空 进行后面的执行
invocation.proceed();
看下它的实现:
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
一个一个的取出拦截器链和对应的methodMatcher,匹配以后才执行拦截器的invoke方法。
dm.interceptor.invoke(this);
Dm就是那个封装拦截器和methodMatcher的对象。调用拦截器的invoke方法。具体是拦截器是哪一种:前置、 后置or 异常,这个是由运行时确定的。
至此AOP源码分析完毕。大结局。