Spring AOP的基本实现方式

​Spring AOP,一种模块化机制,能够动态的对切点添加行为,而不破坏原有的代码结构。

这是一个非常好地动态代理的应用方式。Spring AOP实现依赖于JDK的动态代理库和CGLIB字节码库技术两种来分别实现。

​在Spring AOP中,JdkDynamicAopProxy实现基于JDK动态代理生成代理对象,CglibAopProxy来实现基于CGLIB的动态代理对象生成。并通过DefaultAopProxyFactory进行调用。此处採用策略模式。针对不同场景。调用不同的实现。

例如以下我们对详细实现进行分析。假设对SpringAOP有疑惑的话,能够參考例如以下文章,一篇是我的博客:http://blog.csdn.net/mergades/article/details/46841079 
还有IBM Devloper社区的一篇:http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/

DefaultAopProxyFactory

​Spring AOP内部採用AopProxy对使用不同的代理实现机制进行了适度的抽象,针对不同的代理实现机制提供相应的AopProxy子类实现。DefaultAopProxyFactory实现了AopProxyFactory。当中AopProxyFactory接口定义createAopProxy方法。来决定依据哪种详细的策略来实现代理类。详细实现则由DefaultAopProxyFactory实现,我们查看其相应的createAopProxy方法。

  1. public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
  2. @Override
  3. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  4. if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  5. Class<? > targetClass = config.getTargetClass();
  6. if (targetClass == null) {
  7. throw new AopConfigException("TargetSource cannot determine target class: " +
  8. "Either an interface or a target is required for proxy creation.");
  9. }
  10. if (targetClass.isInterface()) {//假设是接口,则通过JDK的实现,否则通过CGLIB
  11. return new JdkDynamicAopProxy(config);
  12. }
  13. return new ObjenesisCglibAopProxy(config);
  14. }
  15. else {
  16. return new JdkDynamicAopProxy(config);
  17. }
  18. }
  19. /**
  20. * Determine whether the supplied {@link AdvisedSupport} has only the
  21. * {@link org.springframework.aop.SpringProxy} interface specified
  22. * (or no proxy interfaces specified at all).
  23. */
  24. private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
  25. Class<?>[] interfaces = config.getProxiedInterfaces();
  26. return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
  27. }
  28. }
JdkDynamicAopProxy

​基于JDK动态代理的实现。该类实现了InvocationHandler接口。那么我们依据动态代理的知识能够知道,不管调用目标类的什么方法,都会运行该类的Invoke方法,Invoke方法就是Spring AOP增加切面的主要方法。

​我们查看相应的Invoke方法,尽管Invoke方法总体看起来非常长非常复杂,可是仅仅要我们包握住几个重点就可以了解。

  1. @Override
  2. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  3. MethodInvocation invocation;
  4. Object oldProxy = null;
  5. boolean setProxyContext = false;
  6. //1。获取目标对象。
  7. TargetSource targetSource = this.advised.targetSource;
  8. Class<?> targetClass = null;
  9. Object target = null;
  10. //2,推断对JDK原生方法
  11. try {
  12. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
  13. // The target does not implement the equals(Object) method itself.
  14. return equals(args[0]);
  15. }
  16. if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
  17. // The target does not implement the hashCode() method itself.
  18. return hashCode();
  19. }
  20. if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
  21. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
  22. // Service invocations on ProxyConfig with the proxy config...
  23. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
  24. }
  25. Object retVal;
  26. //3,设置代理对象
  27. if (this.advised.exposeProxy) {
  28. // Make invocation available if necessary.
  29. oldProxy = AopContext.setCurrentProxy(proxy);
  30. setProxyContext = true;
  31. }
  32. // May be null. Get as late as possible to minimize the time we "own" the target,
  33. // in case it comes from a pool.
  34. //4,获取目标类
  35. target = targetSource.getTarget();
  36. if (target != null) {
  37. targetClass = target.getClass();
  38. }
  39. // Get the interception chain for this method.
  40. //5,获取通知链
  41. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  42. // Check whether we have any advice. If we don't, we can fallback on direct
  43. // reflective invocation of the target, and avoid creating a MethodInvocation.
  44. //6。推断是否存在通知链。并运行相应方法,获取返回值
  45. if (chain.isEmpty()) {
  46. // We can skip creating a MethodInvocation: just invoke the target directly
  47. // Note that the final invoker must be an InvokerInterceptor so we know it does
  48. // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
  49. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
  50. }
  51. else {
  52. // We need to create a method invocation...
  53. invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  54. // Proceed to the joinpoint through the interceptor chain.
  55. retVal = invocation.proceed();
  56. }
  57. // Massage return value if necessary.
  58. //7,对返回值进行处理
  59. Class<?> returnType = method.getReturnType();
  60. if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
  61. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
  62. // Special case: it returned "this" and the return type of the method
  63. // is type-compatible. Note that we can't help if the target sets
  64. // a reference to itself in another returned object.
  65. retVal = proxy;
  66. } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
  67. throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
  68. }
  69. return retVal;
  70. }
  71. finally {
  72. if (target != null && !targetSource.isStatic()) {
  73. // Must have come from TargetSource.
  74. targetSource.releaseTarget(target);
  75. }
  76. if (setProxyContext) {
  77. // Restore old proxy.
  78. AopContext.setCurrentProxy(oldProxy);
  79. }
  80. }
  81. }

以上是invoke方法的实现。这种方法是动态代理机制较为核心的方法。

以下我们查看在该类中的getProxy方法,查看SpringAOP是怎样获取一个代理对象的。

  1. @Override
  2. public Object getProxy(ClassLoader classLoader) {
  3. if (logger.isDebugEnabled()) {
  4. logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
  5. }
  6. //获代替理接口
  7. Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
  8. //获取是否定义equals和hashCode方法
  9. findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  10. //调用JDK Proxy生成代理
  11. return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  12. }

以上两个方法。我们抛开Spring详细各种细节的实现。全然能够看做是一个简单的动态代理模式的应用。

ObjenesisCglibAopProxy

​ObjenesisCglibAopProxy基于CGLIb的AOP代理对象的生成。在DefaultAopProxyFactory类中,通过调用此方法来实现CGLIB生成代理对象。

  1. @Override
  2. @SuppressWarnings("unchecked")
  3. protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
  4. try {
  5. //详细生成代理,详细实现源代码没有公开
  6. Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass());
  7. factory.setCallbacks(callbacks);
  8. return factory;
  9. }
  10. catch (ObjenesisException ex) {
  11. // Fallback to regular proxy construction on unsupported JVMs
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
  14. }
  15. return super.createProxyClassAndInstance(enhancer, callbacks);
  16. }
  17. }
总结

​如上的各种实现即为Spring AOP对动态代理的应用。我们通过查看以上代码能够看到动态代理的作用,能够不改变原有代码而动态的增加我们自己的操作。这样的方式能够实现对我们代码全然的解耦。

最新文章

  1. 关于android 加载https网页的问题
  2. HDU 2222  AC自动机模板题
  3. ajax基础1
  4. UIWrapContent(NGUI长列表优化利器)
  5. C# 消息队列
  6. 【Git】基本命令使用
  7. css中的选择器
  8. 使用Jenkins构建持续集成环境
  9. mysql优化(一)
  10. Nodejs 动态加载 require
  11. CSS/CSS3长度、时间、频率、角度单位大全
  12. oracle表空间创建及管理
  13. IOS开发之Cocoa编程—— NSUndoManager
  14. bzoj 1030-1039
  15. 利用nodeJs来安装less以及编译less文件为css文件
  16. Spring 为Bean对象执行初始化和销毁方法
  17. Luogu P1860 新魔法药水
  18. [POI2000] 最长公共子串
  19. 最全的Django入门及常用配置
  20. rest-framework的认证组件

热门文章

  1. [Python3网络爬虫开发实战] 3.1-使用urllib
  2. 零基础入门学习Python(33)--异常处理:你不可能总是对的2
  3. 【转】Delphi 文件拖放
  4. DB2隔离级别
  5. dbeaver能执行存储过程,db2命令编辑器里面不行
  6. python3.x Day5 异常处理
  7. winform消息提示框
  8. 杭电 2035 (快速幂) 求A^B的最后三位数表示的整数
  9. 九度oj 题目1190:大整数排序
  10. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)