博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP的实现原理(五)
阅读量:2062 次
发布时间:2019-04-29

本文共 15232 字,大约阅读时间需要 50 分钟。

7、Advice通知的实现

AopProxy代理对象生成时,其拦截器也一并生成。下面我们来分析下Aop是如何对目标对象进行增强的。在为AopProxy配置拦截器的实现中,有一个取得拦截器配置过程,这个过程由DefaultAvisorChainFactory实现的,而这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionA-
dvice方法中,有一个适配器的注册过程,通过配置Spring预先设计好的拦截器,Spring加入了它对Aop实现的处理。为详细了解这个过程,先从Defau-
ltAdvisorChainFactory的实现开始,通过以下代码可以看到,在DefaultAdvisorChainFactory实现中,首先构造了一个GlobalAdvisorAdapterRegistry单件,然后对配置的Advisor通知器进行逐个遍历,这些通知链都是配置在interceptorNames中的,从getInterceptorsAndDynamicInterceptionAdvice传递进来的advised参数对象中,可以方便的取得配置的通知器,有了这些通知器,接着就是一个由
GlobalAdvisorAdapterRegistry来完成的拦截器的适配和注册。

/** * A simple but definitive way of working out an advice chain for a Method, * given an {@link Advised} object. Always rebuilds each advice chain; * caching can be provided by subclasses. * @author Juergen Hoeller * @author Rod Johnson * @author Adrian Colyer * @since 2.0.3 */@SuppressWarnings("serial")public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
public List 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 interceptorList = new ArrayList(config.getAdvisors().length); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); // 得到注册器GlobalAdvisorAdapterRegistry,这是一个单件模式的实现 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(targetClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, 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(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

GlobalAdvisorAdapterRegistry的getInterceptors方法为AOP的实现做出了很大的贡献,这个方法封装着advice织入实现的入口,我们先从GlobalAdvisorAdapterRegistry的实现入手,他基本起一个适配器的作用,但同时也是单件模式,代码如下:

/**     * Keep track of a single instance so we can return it to classes that request it.     */    // 使用静态变量来保持一个唯一实例    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();    /**     * Return the singleton {@link DefaultAdvisorAdapterRegistry} instance.     */    public static AdvisorAdapterRegistry getInstance() {        return instance;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到这里,我们知道在DefaultAdvisorAdapterRegistry中,设置了一系列的adapter适配器,这是这些适配器的实现,为Spring的advice提供了编织能力,下面我们看看DefaultAdvisorAdapterRegistry究竟发生了什么?adapter的作用具体分为两个:

1、调用adapter的support方法,通过这个方法来判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的AdviceInterceptor,也就是前面我们看到的拦截器
2、这些AdviceInterceptor都是Spring AOP框架设计好的,是为实现不同的advice功能提供服务的。有了这些AdviceInterceptor,可以方便的使用由Spring提供的各种不同的advice来设计AOP应用。也就是说,正是这些AdviceInterceptor最终实现了advice通知在AopProxy对象中的织入功能。

/** * Default implementation of the {@link AdvisorAdapterRegistry} interface. * Supports {@link org.aopalliance.intercept.MethodInterceptor}, * {@link org.springframework.aop.MethodBeforeAdvice}, * {@link org.springframework.aop.AfterReturningAdvice}, * {@link org.springframework.aop.ThrowsAdvice}. * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller */@SuppressWarnings("serial")public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List
adapters = new ArrayList
(3); /** * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } 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); } public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List
interceptors = new ArrayList
(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()]); } public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

剥茧抽丝,继续看adapter,在DefaultAdvisorRegistry的getInterceptors调用中,从MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdaper这几个通知适配器的名字上可以看出和Advice一一对应,在这里,他们作为适配器被加入到adapter的List中,他们都是实现AdvisorAdapter接口的同一层次的类,只是各自承担着不同的适配的任务,一对一的服务于不同的advice实现。

以MethodBeforeAdviceAdapter为例,代码如下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } // 把advice从通知器中取出 public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到这里就非常清楚了,Spring AOP为了实现advice的织入,设计了特定拦截器对这些功能进行了封装。虽然应用不会直接用到这些拦截器,但却是advice发挥作用不可缺少的准备。还是以MethodBeforeAdviceInterceptor为例,我们看看advice是如何封装的。在invoke回调方法中,看到首先触发了advice的before的回调,然后才是MethodInvocation的proceed方法的调用。看到这里,就已经和前面的在ReflectionMethodInvocation的Proceed分析中联系起来。回忆了一下,在AopProxy代理对象触发的ReflectionMethodInvocation的proceed方法中,在取得拦截器以后,启动了对拦截器invoke方法的调用。按照AOP的规则,ReflectiveMethodInvocation触发的拦截器invoke方法,最终会根据不同的advice类型,触发Spring对不同的advice的拦截器封装,比如对MethodBeforeAdvice,最终会根据不同的advice类型触发Spring对不同的advice的拦截器封装。比如对MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,会调用advice的before方法,这就是MethodBeforeAdvice所需要的对目标对象的增强效果:在方法调用之前通知增强。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice; /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */ // 为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象 public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } // 这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调 public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

完成MethodBeforeAdviceInterceptor的调用,然后启动advice通知的afterReturning回调,代码如下:

/**     * Create a new AfterReturningAdviceInterceptor for the given advice.     * @param advice the AfterReturningAdvice to wrap     */    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {        Assert.notNull(advice, "Advice must not be null");        this.advice = advice;    }    public Object invoke(MethodInvocation mi) throws Throwable {        Object retVal = mi.proceed();        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());        return retVal;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

ThrowsAdvice的实现和上面类似,也是封装在对应的AdviceInterceptor中,ThrowsAdvice的回调方法要复杂一些,他维护了一个exceptionHandlerMap来对应不同的方法调用场景,这个exceptionHandlerMap中的handler的取得时与触发ThrowsAdvice增强的异常相关的。

/** * Interceptor to wrap an after-throwing advice. * * 

The signatures on handler methods on the {@code ThrowsAdvice} * implementation method argument must be of the form:

* * {@code void afterThrowing([Method, args, target], ThrowableSubclass);} * *

Only the last argument is required. * *

Some examples of valid methods would be: * *

public void afterThrowing(Exception ex)
*
public void afterThrowing(RemoteException)
*
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
*
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
* *

This is a framework class that need not be used directly by Spring users. * * @author Rod Johnson * @author Juergen Hoeller */public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {

private static final String AFTER_THROWING = "afterThrowing"; private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class); private final Object throwsAdvice; /** Methods on throws advice, keyed by exception class */ private final Map
exceptionHandlerMap = new HashMap
(); /** * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice. * @param throwsAdvice the advice object that defines the exception * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice} * implementation) */ public ThrowsAdviceInterceptor(Object throwsAdvice) { Assert.notNull(throwsAdvice, "Advice must not be null"); this.throwsAdvice = throwsAdvice; // 配置ThrowsAdvice回调方法 Method[] methods = throwsAdvice.getClass().getMethods(); for (Method method : methods) { if (method.getName().equals(AFTER_THROWING) && (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) && Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1]) ) { // Have an exception handler // 配置异常处理 this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method); if (logger.isDebugEnabled()) { logger.debug("Found exception handler method: " + method); } } } if (this.exceptionHandlerMap.isEmpty()) { throw new IllegalArgumentException( "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]"); } } public int getHandlerMethodCount() { return this.exceptionHandlerMap.size(); } /** * Determine the exception handle method. Can return null if not found. * @param exception the exception thrown * @return a handler for the given exception type */ private Method getExceptionHandler(Throwable exception) { Class exceptionClass = exception.getClass(); if (logger.isTraceEnabled()) { logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]"); } Method handler = this.exceptionHandlerMap.get(exceptionClass); while (handler == null && !exceptionClass.equals(Throwable.class)) { exceptionClass = exceptionClass.getSuperclass(); handler = this.exceptionHandlerMap.get(exceptionClass); } if (handler != null && logger.isDebugEnabled()) { logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler); } return handler; } public Object invoke(MethodInvocation mi) throws Throwable { try { // 把目标对象方法调用放在try catch中,并在catch中触发, // ThrowsAdvice的回调,把异常接着向外抛出,不做过多的处理 return mi.proceed(); } catch (Throwable ex) { Method handlerMethod = getExceptionHandler(ex); if (handlerMethod != null) { invokeHandlerMethod(mi, ex, handlerMethod); } throw ex; } } // 通过反射启动对ThrowsAdvice回调方法的调用 private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable { Object[] handlerArgs; if (method.getParameterTypes().length == 1) { handlerArgs = new Object[] { ex }; } else { handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex}; } try { method.invoke(this.throwsAdvice, handlerArgs); } catch (InvocationTargetException targetEx) { throw targetEx.getTargetException(); } }}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111

未完待续……

转载地址:http://ffhlf.baihongyu.com/

你可能感兴趣的文章
NGWS runtime 技术基础
查看>>
Linux find 文件查询 用法示例
查看>>
Linux 查看文件大小
查看>>
mysql 命令
查看>>
MySQL执行外部sql脚本文件的命令
查看>>
解决MySql Error Code: 2006
查看>>
查看mysql数据库和表所占用空间
查看>>
Guava Collections使用介绍
查看>>
Ordering犀利的比较器
查看>>
spring+Mybatis+Ehcache整合
查看>>
google guava使用例子/示范(一)
查看>>
joda-time 时间API
查看>>
Joda Time API -2
查看>>
Spring使用Cache、整合Ehcache
查看>>
Chrome调试工具奇淫技
查看>>
30分钟快速掌握Bootstrap
查看>>
如何针对业务做DB优化
查看>>
程序猿都该知道的MySQL秘籍
查看>>
Eclipse全面提速小技巧
查看>>
前端程序员必知的30个Chrome扩展
查看>>