• SPRING 阅读--JdkDynamicAopProxy


    一、简介
      JdkDynamicAopProxy 代理类是spring 默认的JDK动态的代理类实现。它实现了Java 动态代理接口InvocationHandler接口和Spring定义的AopProxy接口。AopProxy定义了返回代理的对象。
    二、阅读
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
       Assert.notNull(config, "AdvisedSupport must not be null");
       if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
          throw new AopConfigException("No advisors and no TargetSource specified");
       }
       this.advised = config;
    }
      从其构造函数来看,该类的入参是AdvisedSupport,并把入参设置到成员变量中。其中AdvisedSupport类是Aop代理的配置管理类,里面包括了代理的对象和被代理对象需要织入的通知Advice.
    从该类实现了AopProxy接口,那么久可以返回代理的对象,其实现如下:
     
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
       if (logger.isTraceEnabled()) {
          logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
       }
       Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
       findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
       return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
      首先从AopProxyUtils.completeProxiedInterfaces工具方法得到需要代理的接口,接着通过findDefinedEqualsAndHashCodeMethods私有方法判断这些需要的代理接口proxiedInterfaces是否重新定义了equals和hashcode方法,并把接口记录到this.equalsDefined 和 this.hashCodeDefined成员变量中。最后核心其实是通过Java的动态代理类Proxy 产生一个代理对象。所以每调用一次getProxy都会产生新的一个代理对象。
      接着我们需要看下的就是InvocationHandler接口的invoke方法是如何实现的。注入和原理如下:
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object oldProxy = null;
       boolean setProxyContext = false;
    
        // 通过this.advised得到代理的目标类,
       TargetSource targetSource = this.advised.targetSource;
       Object target = null;
    
       try {
        // 如何代理接口没有定义equals方法,则调用JdkDynamicAopProxy的重写的equals方法
          if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
             // The target does not implement the equals(Object) method itself.
             return equals(args[0]);
          }
         // 如何代理接口没有定义equals方法,则调用JdkDynamicAopProxy的重写的equals方法
          else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
             // The target does not implement the hashCode() method itself.
             return hashCode();
          }
          //如果该方法申明类是DecoratingProxy,则直接最终的被代理类的类Class
          else if (method.getDeclaringClass() == DecoratingProxy.class) {
             // There is only getDecoratedClass() declared -> dispatch to proxy config.
             return AopProxyUtils.ultimateTargetClass(this.advised);
          }
         //如果目标对象是Advice类型,则直接使用反射进行调用
         //opaque-->标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
    
          else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
             // Service invocations on ProxyConfig with the proxy config...
             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
          }
    
          Object retVal;
         //  看是否需要暴露代理对象,如果需要放到threadLocal上
          if (this.advised.exposeProxy) {
             // Make invocation available if necessary.
             oldProxy = AopContext.setCurrentProxy(proxy);
             setProxyContext = true;
          }
    
          // Get as late as possible to minimize the time we "own" the target,
          // in case it comes from a pool.
          target = targetSource.getTarget();
          Class<?> targetClass = (target != null ? target.getClass() : null);
    
          // 得到该调用方法的拦截链
          List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
          // Check whether we have any advice. If we don't, we can fallback on direct
          // reflective invocation of the target, and avoid creating a MethodInvocation.
          // 如果拦截链为空,直接返回调到该方法
         if (chain.isEmpty()) {
             // We can skip creating a MethodInvocation: just invoke the target directly
             // Note that the final invoker must be an InvokerInterceptor so we know it does
             // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
             Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
          }
          else {
             // 否则创建 MethodInvocation 执行拦截调用
             MethodInvocation invocation =
                   new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
             // Proceed to the joinpoint through the interceptor chain.
             retVal = invocation.proceed();
          }
    
          // Massage return value if necessary.
          Class<?> returnType = method.getReturnType();
          if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
             // Special case: it returned "this" and the return type of the method
             // is type-compatible. Note that we can't help if the target sets
             // a reference to itself in another returned object.
             // 如果返回值是this,那么返回值替换为代理对象,而不是原对象。
             retVal = proxy;
          }
          else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
             throw new AopInvocationException(
                   "Null return value from advice does not match primitive return type for: " + method);
          }
          return retVal;
       }
       finally {
          if (target != null && !targetSource.isStatic()) {
             // Must have come from TargetSource.
             targetSource.releaseTarget(target);
          }
          if (setProxyContext) {
             // Restore old proxy.
             AopContext.setCurrentProxy(oldProxy);
          }
       }
    }
      从上面我们知道有几个特殊的接口,当方法的代理类是DecoratingProxy,或者是Advised都做了特殊的处理。原因在于在创建JdkDynamicAopProxy 对象是,有Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 这么一句语句。它返回的代理接口就可能包括DecortingProxy 和Advised。具体如下:
    static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
       Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
       // 首先得到用户设置的代理接口,如果没有检查和设置代理类是否是一个接口
       if (specifiedInterfaces.length == 0) {
          // No user-specified interfaces: check whether target class is an interface.
          Class<?> targetClass = advised.getTargetClass();
          if (targetClass != null) {
             if (targetClass.isInterface()) {
                advised.setInterfaces(targetClass);
             }
             else if (Proxy.isProxyClass(targetClass)) {
                advised.setInterfaces(targetClass.getInterfaces());
             }
             specifiedInterfaces = advised.getProxiedInterfaces();
          }
       }
       // 如果用户代理的接口设置中没有SpringProxy接口,需要把代理类实现SpringProxy接口,该接口是个标记接口,说明是Spring代理
       boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
      // 如果代理类可以转化为Advised类型,并且用户没有指定Advised,则添加该接口,
      //所以这里可以知道一般Spring的代理类都实现了该Advised接口
       boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
      //如果decoratingProxy==true,并且用户未添加DecoratingProxy接口,则代理需要实现该接口DecoratingProxy
       boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
       int nonUserIfcCount = 0;
       if (addSpringProxy) {
          nonUserIfcCount++;
       }
       if (addAdvised) {
          nonUserIfcCount++;
       }
       if (addDecoratingProxy) {
          nonUserIfcCount++;
       }
       Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
       System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
       int index = specifiedInterfaces.length;
       if (addSpringProxy) {
             proxiedInterfaces[index] = SpringProxy.class;
             index++;
          }
          if (addAdvised) {
             proxiedInterfaces[index] = Advised.class;
             index++;
       }
       if (addDecoratingProxy) {
          proxiedInterfaces[index] = DecoratingProxy.class;
       }
       // 所以从上面分析得知,proxiedInterfaces会返回用户制定的代理接口+SpringProxy、Advised、DecoratingProxy 
       return proxiedInterfaces;
    }
    三、测试 
    public interface Human {
    	Human getInstance();
    }
    

      

    public class ChineseHuman implements Human {
    
    	private String desc;
    
    	public ChineseHuman() {
    	}
    
    	public ChineseHuman(String desc) {
    		this.desc = desc;
    	}
    
    	public String getDesc() {
    		return desc;
    	}
    
    	public void setDesc(String desc) {
    		this.desc = desc;
    	}
    
    	@Override
    	public Human getInstance() {
    		System.out.println("human desc:" + desc);
    		return this;
    	}
    }
    

      

    public class JdkDynamicAopProxyTests {
    
    	@Test
    	public void testJdkProxy() {
    		AdvisedSupport advisedSupport = new AdvisedSupport();
    		advisedSupport.setInterfaces(Human.class);
    		advisedSupport.setTargetSource(new TargetSource() {
    			@Override
    			public Class<?> getTargetClass() {
    				return ChineseHuman.class;
    			}
    
    			@Override
    			public boolean isStatic() {
    				return false;
    			}
    
    			@Override
    			public Object getTarget() throws Exception {
    				return new ChineseHuman("中国人");
    			}
    
    			@Override
    			public void releaseTarget(Object target) throws Exception {
    
    			}
    		});
    		JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
    
    		Human human = (Human) Proxy.newProxyInstance(JdkDynamicAopProxy.class.getClassLoader(), new Class[]{Human.class}, jdkDynamicAopProxy);
    
    		System.out.println(human.getInstance());
    
    		// JDK原生代理,必然为true,因为本身是生成的是代理的接口的对象
    		System.out.println("human instanceof Human:" + (human instanceof Human));
    
    		//false
    		System.out.println("human instanceof ChineseHuman:" + (human instanceof ChineseHuman));
    		//false
    		System.out.println("human instanceof Advised:" + (human instanceof Advised));
    		//false
    		System.out.println("human instanceof SpringProxy:" + (human instanceof SpringProxy));
    		//false
    		System.out.println("human instanceof DecoratingProxy:" + (human instanceof DecoratingProxy));
    		//true, 有个面试题是这么问的,java动态代理为啥代理是接口,不能是类,
    		// 其根原在于JDK的动态代理实现方式是代理对象继承了java.lang.reflect.Proxy,并且java单继承,所以无法代理类
    		System.out.println("human instanceof Proxy:" + (human instanceof Proxy));
    
    		System.out.println("Spring JDK代理扩展=========");
    
    		human = (Human) jdkDynamicAopProxy.getProxy();
    
    		System.out.println(human.getInstance());
    
    		// 该代理对象的getInstance返回是其本身,原因也在于上面分析的红色部分原因。
    		System.out.println("human== human.getInstance():" + (human == human.getInstance()));
    		
    		// true
    		System.out.println("human instanceof Human:" + (human instanceof Human));
    		//false
    		System.out.println("human instanceof ChineseHuman:" + (human instanceof ChineseHuman));
    		//true 
    		System.out.println("human instanceof Advised:" + (human instanceof Advised));
    		// true
    		System.out.println("human instanceof SpringProxy:" + (human instanceof SpringProxy));
    		// true
    		System.out.println("human instanceof DecoratingProxy:" + (human instanceof DecoratingProxy));
    		//true
    		System.out.println("human instanceof Proxy:" + (human instanceof Proxy));
    	}
    }
    

      从上面的测试可以知道,一个对象被Spring的JDK动态代理后,其代理对象会实现其用户指定的代理接口外,还会实现Advised,SpringProxy,DecoratingProxy接口。

     
     
     
     
  • 相关阅读:
    c# Action,Func,Predicate委托
    c# 匿名方法
    IIS网站无法启动,提示 另一个程序正在使用此文件
    c# Http下载
    mciSendString详解(转)
    【NOIP2006PJ】数列(sequence)题解
    2020.04.29【NOIP普及组】模拟赛C组30总结
    【USACO 2019 December Silver】Milk Visits题解
    【USACO 2019 February Bronze】Measuring Traffic 题解
    【USACO 2019 February Bronze】Measuring Traffic 题解
  • 原文地址:https://www.cnblogs.com/liferecord/p/13384496.html
Copyright © 2020-2023  润新知