zoukankan      html  css  js  c++  java
  • Spring AOP 多个切点实现:JdkDynamicAopProxy

    Spring Aop 的底层生成代理类i的实现除 jdk的动态代理技术外,还用到了Cglib,不过在封装两者的设计原理上相差不大,只是底层工具不同而已。

    本文只分析JdkDynamicAopProxy 是如何为一个目标方法执行织入多个切点,也就是将原本可能需要多个“代理类“实现的业务放到一个代理类中(JdkDynamicAopProxy)完成。

    JdkDynamicAopProxy 本身就是一个JDK代理的InvocationHandler,spring 在调用其getProxy()方法返回一个代理类对象时:

    public Object getProxy(ClassLoader classLoader) {
            if (logger.isDebugEnabled()) {
                logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
            }
            Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 传入的 Handler 就是this,也就是 一个 JdkDynamicAopProxy 对象。所以代理的业务就在 JdkDynamicAopProxy
    invoke()方法上。
     1 /**
     2      * Implementation of <code>InvocationHandler.invoke</code>.
     3      * <p>Callers will see exactly the exception thrown by the target,
     4      * unless a hook method throws an exception.
     5      */
     6     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     7         MethodInvocation invocation;
     8         Object oldProxy = null;
     9         boolean setProxyContext = false;
    10 
    11         TargetSource targetSource = this.advised.targetSource;
    12         Class targetClass = null;
    13         Object target = null;
    14 
    15         try {
    16             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    17                 // The target does not implement the equals(Object) method itself.
    18                 return equals(args[0]);
    19             }
    20             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    21                 // The target does not implement the hashCode() method itself.
    22                 return hashCode();
    23             }
    24             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    25                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    26                 // Service invocations on ProxyConfig with the proxy config...
    27                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    28             }
    29 
    30             Object retVal;
    31 
    32             if (this.advised.exposeProxy) {
    33                 // Make invocation available if necessary.
    34                 oldProxy = AopContext.setCurrentProxy(proxy);
    35                 setProxyContext = true;
    36             }
    37 
    38             // May be null. Get as late as possible to minimize the time we "own" the target,
    39             // in case it comes from a pool.
    40             target = targetSource.getTarget();
    41             if (target != null) {
    42                 targetClass = target.getClass();
    43             }
    44 
    45             // Get the interception chain for this method.
    46             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    47 
    48             // Check whether we have any advice. If we don't, we can fallback on direct
    49             // reflective invocation of the target, and avoid creating a MethodInvocation.
    50             if (chain.isEmpty()) {
    51                 // We can skip creating a MethodInvocation: just invoke the target directly
    52                 // Note that the final invoker must be an InvokerInterceptor so we know it does
    53                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
    54                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
    55             }
    56             else {
    57                 // We need to create a method invocation...
    58                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    59                 // Proceed to the joinpoint through the interceptor chain.
    60                 retVal = invocation.proceed();
    61             }
    62 
    63             // Massage return value if necessary.
    64             if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
    65                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    66                 // Special case: it returned "this" and the return type of the method
    67                 // is type-compatible. Note that we can't help if the target sets
    68                 // a reference to itself in another returned object.
    69                 retVal = proxy;
    70             }
    71             return retVal;
    72         }
    73         finally {
    74             if (target != null && !targetSource.isStatic()) {
    75                 // Must have come from TargetSource.
    76                 targetSource.releaseTarget(target);
    77             }
    78             if (setProxyContext) {
    79                 // Restore old proxy.
    80                 AopContext.setCurrentProxy(oldProxy);
    81             }
    82         }
    83     }
    invoke方法中的红色加粗代码就是重点部分:

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    该行代码是构建代理链,获取到目标方法需要增强的一系列业务代理对象。

    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    通过将目标方法和 多个业务代理对象 创建成一个
    ReflectiveMethodInvocation,来实际完成 执行目标方法时执行一些拦截器,也就是代理业务。


    retVal = invocation.proceed();
    该行代码开始执行代理业务和目标方法。

    下面是
    ReflectiveMethodInvocation 的 proceed方法代码:
     1 public Object proceed() throws Throwable {
     2         //    We start with an index of -1 and increment early.
     3         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
     4             return invokeJoinpoint();
     5         }
     6 
     7         Object interceptorOrInterceptionAdvice =
     8             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
     9         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    10             // Evaluate dynamic method matcher here: static part will already have
    11             // been evaluated and found to match.
    12             InterceptorAndDynamicMethodMatcher dm =
    13                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    14             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    15                 return dm.interceptor.invoke(this);
    16             }
    17             else {
    18                 // Dynamic matching failed.
    19                 // Skip this interceptor and invoke the next in the chain.
    20                 return proceed();
    21             }
    22         }
    23         else {
    24             // It's an interceptor, so we just invoke it: The pointcut will have
    25             // been evaluated statically before this object was constructed.
    26             return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    27         }
    28     }

    可以看到proceed()方法通过从interceptorsAndDynamicMethodMatchers(list)集合中取出拦截器,拦截器是在前面创建ReflectiveMethodInvocation对象时传入的chain,

    通过判断拦截器集合中所有拦截器是否执行完,未执行完这递归调用proceed()方法,执行完则执行目标方法。

    以上就是JdkDynamicAopProxy实现多个拦截器拦截目标方法的动态代理业务。

    
    
     
     
     


  • 相关阅读:
    PHP 载入图像 imagecreatefrom_gif_jpeg_png 系列函数
    PHP 输出图像 imagegif 、imagejpeg 与 imagepng 函数
    php实现等比例不失真缩放上传图片
    PHP开发框架--CodeIgniter(CI)使用总结
    将Centos的yum源更换为国内的阿里云源
    开始投资的活动条件是什么
    复利效应 每天进步一点点到底指的是什么?
    你拥有的最宝贵的财富是什么?
    自律真的可以改变人生
    chpasswd-批量修改用户密码
  • 原文地址:https://www.cnblogs.com/xuzimian/p/10910784.html
Copyright © 2011-2022 走看看