`
m635674608
  • 浏览: 4928305 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

spring 代理对象方法增强源码解析

 
阅读更多
在spring中有两种产生代理对象的方式: AopProxy的子类:Cglib2AopProxy和JdkDynamicAopProxy。 1. Jdk主要是:Proxy.newProxyInstance(classLoader, proxiedInterfaces, InvocationHandler); 2. Cglib则是通过Enhancer类来实现的。 它们有个相同点就是都有一个回调方法。我们可以在回调方法中对目标方法进行增强。 JDK代理对象的回调 1. public Object invoke(Object proxy, Method method, Object[] 2. args) throws Throwable { 3. MethodInvocation invocation = null; 4. Object oldProxy = null; 5. boolean setProxyContext = false; 6. TargetSource targetSource = 7. this.advised.targetSource; 8. Class targetClass = null; 9. Object target = null; 10. try { 11. if (!this.equalsDefined && 12. AopUtils.isEqualsMethod(method)) { 13. // The target does not implement the 14. equals(Object) method itself. 15. return equals(args[0]); 16. } 17. if (!this.hashCodeDefined && 18. AopUtils.isHashCodeMethod(method)) { 19. // The target does not implement the 20. hashCode() method itself. 21. return hashCode(); 22. } 23. if (!this.advised.opaque && 24. method.getDeclaringClass().isInterface() && 25. 26. method.getDeclaringClass().isAssignableFrom(Advised.class)) 27. { 28. // Service invocations on 29. ProxyConfig with the proxy config... 30. return 31. AopUtils.invokeJoinpointUsingReflection(this.advised, 32. method, args); 33. } 34. Object retVal = null; 35. if (this.advised.exposeProxy) { 36. // Make invocation available if 37. necessary. 38. oldProxy = 39. AopContext.setCurrentProxy(proxy); 40. setProxyContext = true; 41. } 42. /** 43. * May be null. Get as late as possible to 44. minimize the time we "own" the 45. * target, in case it comes from a pool. 46. */ 47. //得到目标对象的地方。 48. target = targetSource.getTarget(); 49. if (target != null) { 50. targetClass = target.getClass(); 51. } 52. // Get the interception chain for this 53. method. 54. // 这里获得定义好的拦截器链。 55. List chain = 56. this.advised.getInterceptorsAndDynamicInterception 57. Advice(method, targetClass); 58. /** 59. * Check whether we have any advice. If we 60. don't, we can fallback on 61. * direct reflective invocation of the 62. target, and avoid creating a MethodInvocation. 63. */ 64. 65. // 66. 如果没有设定拦截器,那么我们就直接调用target的对应方法。 67. if (chain.isEmpty()) { 68. /** 69. * We can skip creating a 70. MethodInvocation: just invoke the target directly 71. * Note that the final invoker must 72. be an InvokerInterceptor so we 73. * know it does nothing but a 74. reflective operation on the target, and no hot 75. * swapping or fancy proxying. 76. */ 77. retVal = 78. AopUtils.invokeJoinpointUsingReflection(target, method, 79. args); 80. } 81. else { 82. // We need to create a method 83. invocation... 84. /** 85. * 86. 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相 87. 应方法, 88. * 89. 通过构造一个ReflectiveMethodInvocation来实现,下面我们会看 90. * 91. 这个ReflectiveMethodInvocation类的具体实现。 92. */ 93. invocation = new 94. ReflectiveMethodInvocation(proxy, target, method, 95. args, targetClass, chain); 96. // Proceed to the joinpoint through 97. the interceptor chain. 98. //沿着拦截器链继续前进。 99. retVal = invocation.proceed(); 100. } 101. 102. // Massage return value if necessary. 103. if (retVal != null && retVal == target && 104. method.getReturnType(). 105. isInstance(Proxy) && 106. !RawTargetAccess.class.isAssignableFrom 107. (method.getDeclaringClass())) { 108. /** 109. * Special case: it returned "this" 110. and the return type of the method 111. * is type-compatible. Note that we 112. can't help if the target sets 113. * a reference to itself in another 114. returned object. 115. */ 116. retVal = Proxy; 117. } 118. return retVal; 119. } 120. finally { 121. if (target != null && 122. !targetSource.isStatic()) { 123. // Must have come from TargetSource. 124. targetSource.releaseTarget(target); 125. } 126. if (setProxyContext) { 127. // Restore old proxy. 128. 129. AopContext.setCurrentProxy(oldProxy); 130. } 131. } 132. } Cglib代理对象的回调方法: 1. public Object intercept(Object proxy, Method method, 2. Object[] args, MethodProxy 3. methodProxy) throws Throwable { 4. Object oldProxy = null; 5. boolean setProxyContext = false; 6. Class targetClass = null; 7. Object target = null; 8. try { 9. if (this.advised.exposeProxy) { 10. // Make invocation available if 11. necessary. 12. oldProxy = 13. AopContext.setCurrentProxy(proxy); 14. setProxyContext = true; 15. } 16. /** 17. * May be null. Get as late as 18. possible to minimize the time we 19. * "own" the target, in case it comes from a 20. pool. 21. */ 22. target = getTarget(); 23. if (target != null) { 24. targetClass = target.getClass(); 25. } 26. //从advised中取得配置好的AOP通知。 27. List chain = 28. this.advised.getInterceptorsAndDynamicInterceptionAdvice 29. (method, targetClass); 30. Object retVal = null; 31. /** 32. * Check whether we only have one 33. InvokerInterceptor: that is, 34. * no real advice, but just reflective 35. invocation of the target. 36. */ 37. // 38. 如果没有AOP通知配置,那么直接调用target对象的调用方法。 39. if (chain.isEmpty() && 40. Modifier.isPublic(method.getModifiers())) { 41. /** 42. * We can skip creating a 43. MethodInvocation: just invoke the target directly. 44. * Note that the final invoker must 45. be an InvokerInterceptor, so we know 46. * it does nothing but a reflective 47. operation on the target, and no hot 48. * swapping or fancy proxying. 49. */ 50. retVal = methodProxy.invoke(target, 51. args); 52. } 53. else { 54. 55. //通过CglibMethodInvocation来启动advice通知。 56. retVal = new 57. CglibMethodInvocation(proxy, target, method, args, 58. targetClass, chain, methodProxy).proceed(); 59. } 60. retVal = massageReturnTypeIfNecessary(proxy, 61. target, method, retVal); 62. return retVal; 63. } 64. finally { 65. if (target != null) { 66. releaseTarget(target); 67. } 68. if (setProxyContext) { 69. // Restore old proxy. 70. 71. AopContext.setCurrentProxy(oldProxy); 72. } 73. } 74. } 在调用代理目标对象的方法时;都对方法进行了增强。 75. //从advised中取得配置好的AOP通知。 76. List chain = 77. this.advised.getInterceptorsAndDynamicInterceptionAdvice (method, targetClass); 在这里可以设置不同的拦截器进行不同的业务处理。比如记录日志,事物的开启… 这就是Aop的核心。具体是由相关的拦截器完成的。 在jdk,cglib代理类中都有一个拦截链处理器,它们分别是 JDK代理类拦截链处理器: 133. 这个ReflectiveMethodInvocation类的具体实现。 134. */ 135. ReflectiveMethodInvocation invocation = new 136. ReflectiveMethodInvocation(proxy, target, method, 137. args, targetClass, chain); 138. //沿着拦截器链继续前进。 retVal = invocation.proceed(); CGLIB代理类拦截链处理器: 78. //通过CglibMethodInvocation来启动advice通知。 79. retVal = new 80. CglibMethodInvocation(proxy, target, method, args, 81. targetClass, chain, methodProxy).proceed(); 82. } 83. retVal = massageReturnTypeIfNecessary(proxy, 84. target, method, retVal); JDK代理类拦截链处理器的proceed方法: 1. public Object proceed() throws Throwable { 2. // We start with an index of -1 and increment 3. early. 4. /** 5. *如果拦截器链中的拦截器迭代调用完毕,这里开始调用tar 6. get的函数, 7. *这个函数是通过反射机制完成的,具体实现在:AopUtils. 8. invokeJoinpointUsingReflection方法里面。 9. */ 10. if (this.currentInterceptorIndex == 11. this.interceptorsAndDynamicMethod 12. Matchers.size() - 1) { 13. return invokeJoinpoint(); 14. } 15. //这里沿着定义好的 16. interceptorOrInterceptionAdvice链进行处理。 17. Object interceptorOrInterceptionAdvice = 18. this.interceptorsAndDynamicMethodMatchers.get(++this 19. .currentInterceptor 20. Index); 21. if (interceptorOrInterceptionAdvice instanceof 22. InterceptorAndDynamic 23. MethodMatcher) { 24. /** 25. * Evaluate dynamic method matcher here: 26. static part will already have 27. * been evaluated and found to match. 28. */ 29. /** 30. 31. *这里对拦截器进行动态匹配的判断,还记得我们前面分析的pointcu 32. t吗? 33. 34. *这里是触发进行匹配的地方,如果和定义的pointcut匹配,那么这 35. 个advice将会得到执行。 36. */ 37. InterceptorAndDynamicMethodMatcher dm = 38. (InterceptorAndDynamicMethodMatcher) 39. interceptorOrInterceptionAdvice; 40. if (dm.methodMatcher.matches(this.method, 41. this.targetClass, this.arguments)) { 42. return dm.interceptor.invoke(this); 43. } 44. else { 45. // Dynamic matching failed. 46. // Skip this interceptor and invoke 47. the next in the chain. 48. // 49. 如果不匹配,那么proceed会被递归调用,直到所有的拦截器都被运 50. 行过为止。 51. return proceed(); 52. } 53. }
  • 描述: 相关拦截器
  • 大小: 91.4 KB
1
4
分享到:
评论
1 楼 sweat89 2012-11-05  
注意排版行不,,,,看起来就像一坨屎

相关推荐

    Spring中文帮助文档

    2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. ...

    Spring API

    2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. ...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java开源包4

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包8

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    javaee底层源码-myframe:后端Java,前端JavaScript,将开源框架的思想,实现在自己的个人项目中,从而提升自己的编程水平

    :如同spring容器那样,实现了反转控制和依赖注入功能,作为应用程序中对象的容器,它可将Bean单例化,并为Bean提供代理,在切面处增强功能,不过目前只支持事务,此外,这样的框架也能很好地解耦模块之间的关系,并...

    java开源包1

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包11

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包2

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包3

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包6

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包5

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包10

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包7

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包9

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包101

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    Java资源包01

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    asp.net知识库

    动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/catch语句带来的warning 微软的应试题完整版(附答案) 一个时间转换的问题,顺便谈谈搜索技巧 .net中的正则表达式使用高级技巧 (一) C#静态成员和...

Global site tag (gtag.js) - Google Analytics