Spring AOP 源码分析 part4 :拦截器的实现
来源:互联网 发布:python pdf 文字水印 编辑:程序博客网 时间:2024/06/10 17:21
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源码分析完毕。大结局。
- Spring AOP 源码分析 part4 :拦截器的实现
- Spring AOP源码分析(拦截器调用的实现)
- Spring源码分析-AOP拦截器链的使用(六)
- Spring AOP 拦截器的基本实现
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring源码分析之Aop中拦截器,适配器,通知之间的关系
- Spring源码分析:实现AOP- -
- Spring实现AOP源码分析
- Spring AOP实现之拦截器调用的实现
- spring的aop拦截器
- spring AOP中对拦截器调用的实现
- Spring学习笔记<四> AOP 拦截器的基本实现
- AOP的实现:Spring注解形式拦截
- 基于Spring源码分析AOP的实现机制
- Spring AOP拦截器调用实现
- Spring Aop原理分析(二) - Aop的拦截器和通知
- Spring aop拦截器
- spring aop源码分析
- 8.2 聚类(Clustering) K-means算法应用
- JSP生成responseXML
- JPA事务处理(坑)
- SCU2016-02 K 双指针
- ArcGis for Android 开发
- Spring AOP 源码分析 part4 :拦截器的实现
- https 与 http
- javascript函数作用域和变量声明提前(variable hoisting)
- ROS相关解释
- html与css
- 走遍欧洲 —— 北欧(挪威、瑞典、芬兰,丹麦,冰岛)
- 手机里竟然有这么多传感器!终于都搞懂了
- SCU2016-02 E 动态贪心
- 扩展SpringMVC以支持绑定JSON格式的请求参数