动态代理3--Spring AOP分析

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对动态代理的应用,我们通过查看以上代码可以看到动态代理的作用,可以不改变原有代码而动态的加入我们自己的操作,这种方式可以实现对我们代码完全的解耦。



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值