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



  • 相关阅读:
    linux C总结篇(进程)
    进程与线程的区分
    递归的两种思路
    Linux下git与github的一般使用
    文件读写和文件指针的移动
    文件的创建,打开与关闭
    一个简单脚本
    linux 三剑客命令(grep,sed ,awk)
    常用正则表达式
    PAT:1002. A+B for Polynomials (25) 部分错误
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6848355.html
Copyright © 2020-2023  润新知