精华内容
下载资源
问答
  • jdk动态代理模式:主要通过接口...代理模式的实现底层是反射 /**Description: jdk动态代理类 / public class DynamicProxy implements InvocationHandler{ //被代理类的实例 private IUserDao iud=null; ...

    参考文档:  https://www.cnblogs.com/teach/p/10763845.html

     

    jdk动态代理模式:主要通过接口,获取到被代理类的对象。可以在这个对象调用方法的前后做一些增强处理

    代理模式的实现底层是反射

     
    /**Description: jdk动态代理类 /
     
    public class DynamicProxy implements InvocationHandler{
        //被代理类的实例
        private IUserDao iud=null;
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // TODO Auto-generated method stub
            Object result=null;
            System.out.println("开始JDK动态代理");
            method.invoke(iud, args);
            System.out.println("结束JDK动态代理");
            return result;
        }
        //构造方法
        public DynamicProxy(IUserDao iud){
            this.iud=iud;
        }
        
    }

     

    public class Test2 {
    
        public static void main(String[] args) {
          
            UserDao ud=new UserDao();
            
            DynamicProxy dp=new DynamicProxy(ud);
            
            //生成代理对象
            IUserDao iud=(IUserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), dp);
            iud.save();
            System.out.println("--------------");
            iud.find();
            
        }
    }

    1.被代理的类实现一个接口

    2.生成代理类对象的方法参数依次是:

    第一个为被代理类的类加载器,第二个为被代理类实现的接口,第三个则为invocationHandler的实现类 

     

    cglib动态代理:

    CGLib动态代理是一个第三方实现的动态代理类库,不要求被代理类必须实现接口,它采用的是继承被代理类,使用其子类的方式,弥补了被代理类没有接口的不足

     

    可以看出使用Enhancer生成代理类,需要设置被代理类,也就是父类(可以看出是使用继承,生成的子类),设置回调方法

    public class MyMethodInterceptor implements MethodInterceptor {
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            // TODO Auto-generated method stub
            
            System.out.println("开始CGLib动态代理");
            Object object=proxy.invokeSuper(obj, args);
            System.out.println("结束CGLib动态代理");
            return object;
        }
    
    }

     

    public class Test {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(UserDao.class);
            enhancer.setCallback(new MyMethodInterceptor());
            //生成代理类
            UserDao ud=(UserDao) enhancer.create();
            ud.save();
            System.out.println("----------------");
            ud.find();
            
        }
    
    }

     

    展开全文
  • 代理模式 Jdk动态代理 通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用创建代理对象时,需要传递该业务类类加载器(用来获取业务实现元数据,在包装方法是调用真正业务方法)、接口、...

    代理模式

    Jdk动态代理

    通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类,被代理的对象必须实现了某一个接口。

    public <T> T getProxy(T target) {
    		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
    				target.getClass().getInterfaces(), new MyInvocationHandler(
    						target));
    	}
    

    CGLIB动态代理

    一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,通过增强器Enhancer和拦截器MethodInterceptor去实现。
    创建代理的步骤:
    生成代理类的二进制字节码文件;
    加载二进制字节码,生成Class对象;
    通过反射机制获得实例构造,并创建代理类对象

    public static <T> T getObjectProxy(T target, Callback[] callbacks,
    			CallbackFilter filter) {
    		// 1、创建加强器用来创建动态代理
    		Enhancer enhancer = new Enhancer();
    		// 2 、为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
    		enhancer.setSuperclass(target.getClass());
    		// 3、 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
    		// 3.1callback用于类的所有方法进行加强后返回
    		// enhancer.setCallback(callback);
    		// 3.2callbacks对指定的方法进行拦截,需要配置拦截链CallbackFilter
    		enhancer.setCallbacks(callbacks);
    		enhancer.setCallbackFilter(filter);
    		// 4、创建动态代理类对象并返回
    		return (T) enhancer.create();
    	}
    

    Spring创建动态代理

    AbstractAutoProxyCreator根据配置获取到所有可以引用bean的增强器List以后,就需要为bean创建代理,Spring代理又分为JDK动态代理和CGLIB动态代理两种方式,所以按照常规方式,需要一个ProxyFactory去根据需求创建具体的Proxy对象,Spring也是这么去做的。

    protected Object createProxy(
    			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
    		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    		}
    	  	//1、获取当前类钟的属性
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
    		//2、添加代理接口
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
    		//3、封装Advisor到ProxyFactory中
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		for (Advisor advisor : advisors) {
    			proxyFactory.addAdvisor(advisor);
    		}
    		//4、设置要代理的类
    		proxyFactory.setTargetSource(targetSource);
    		//5、定制代理,子类扩展方法
    		customizeProxyFactory(proxyFactory);
    
    		proxyFactory.setFrozen(this.freezeProxy);
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
    		//6、进行获取代理
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}
    

    创建代理的过程

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    			Class<?> targetClass = config.getTargetClass();
    			if (targetClass == null) {
    				throw new AopConfigException("TargetSource cannot determine target class: " +
    						"Either an interface or a target is required for proxy creation.");
    			}
    			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}
    

    optimize:默认false,用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP代理如何处理优化,否则不推荐使用这个设置,目前这个属性仅仅用于CGLIB代理,JDK动态代理无效。
    proxyTargetClass:默认false,<aop:aspectj-autoproxy />有一个proxy-target-class属性,当该值被设置为true时,CGLIB代理将被创建。
    hasNoUserSuppliedProxyInterfaces:是否存在代理接口,代理目标没有实现接口,或者仅有一个SpringProxy接口时返回true。

    CGLIB与动态代理的区别:
    1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
    2、CGLIB是针对类实现代理,主要是针对指定类生成一个子类,覆盖其中的方法,因为是继承关系,所欲该类或刚发最好不要声明成final(不能被子类继承)。

    无论是ObjenesisCglibAopProxy还是JdkDynamicAopProxy都实现了AopProxy,都有一个AdvisedSupport,也是前面已经初始化过的ProxyFactory。

    JdkDynamicAopProxy

    实现了AopProxy,同时InvocationHandler接口,核心方法就两个:
    getProxy:获取代理
    invoke:目标方法在调用时进行拦截。

    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);
    	}
    
    被代理的类自调用

    SpringAop在运行过程中通过动态代理进入到invoke,然后判断是否需要进行方法拦截,需要的时候才会根据配置生成拦截器链。但自调用是没有代理对象的,在spring的事物处理中,有时候出现类似的问题,我们可以通过<aop:aspectj-autoproxy expose-proxy=“true”/>在自调用的时候将代理对象暴露出来。
    原案例:

    public String getStr(String str) {
    		clear();
    		return str;
    	}
    
    public class TestAop {
    	public static void main(String[] args) {
    		ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/aop/spring-aop.xml");
    		TestC c = ctx.getBean(TestC.class);
    		c.getStr("test");
    	}
    	// 配置 <aop:aspectj-autoproxy expose-proxy="false"/>
    

    结果:
    Constructor of TestC
    LogBean#beforePoint

    使用<aop:aspectj-autoproxy expose-proxy=“true”/>

    public String getStr() {
    		TestC testC = (TestC)AopContext.currentProxy();
    		testC.clear();
    		return str;
    	}
    

    结果:
    Constructor of TestC
    LogBean#beforePoint
    LogBean#beforePoint

    expose-proxy="true"是在什么时候通过什么样的方式将自调用的代理给暴露出来的,其原理就在JdkDynamicAopProxy的invoke方法中,通过判断expose-proxy的值,是否将当前对象的代理给暴露出来。

    // 其余代码省略
    if (this.advised.exposeProxy) {
    				// Make invocation available if necessary.
    				oldProxy = AopContext.setCurrentProxy(proxy);
    				setProxyContext = true;
    			}
    // 其余代码省略
    if (setProxyContext) {
    				// Restore old proxy.
    				AopContext.setCurrentProxy(oldProxy);
    			}
    

    至于invoke方法中,关于如何将增强器封装成拦截器链,然后通过递归去实现责任链的方式就不仔细详解,想知道具体的方法,可以去看DefaultAdvisorChainFactory关于这一段的实现。

    // We need to create a method invocation...
    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // Proceed to the joinpoint through the interceptor chain.
    retVal = invocation.proceed();
    

    CglibAopProxy

    与JDK动态代理不同的是,CglibAopProxy除了实现AopProxy并没实现其它特别接口。是通过MethodInterceptor来实现方法的拦截,与jdk动态代理处理的方式一模一样。
    包含的步骤:
    1、是否需要创建代理;
    2、Object类的方法处理;
    3、expose-proxy="true"的处理;
    4、将Advisor封装成ReflectiveMethodInvocation(拦截器链)对代理对象进行处理。

    CglibAopProxy的getCallbacks方法中最核心的一段代码:

    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    // ... 省略
    Callback[] mainCallbacks = new Callback[] {
    				aopInterceptor,  // for normal advice
    				targetInterceptor,  // invoke target without considering advice, if optimized
    				new SerializableNoOp(),  // no override for methods mapped to this
    				targetDispatcher, this.advisedDispatcher,
    				new EqualsInterceptor(this.advised),
    				new HashCodeInterceptor(this.advised)
    		};
    

    进入DynamicAdvisedInterceptor能感受到其本质与jdk动态代理是一致的。

    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
    
    		private final AdvisedSupport advised;
    
    		public DynamicAdvisedInterceptor(AdvisedSupport advised) {
    			this.advised = advised;
    		}
    
    		@Override
    		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    			Object oldProxy = null;
    			boolean setProxyContext = false;
    			Class<?> targetClass = null;
    			Object target = null;
    			try {
    				if (this.advised.exposeProxy) {
    					// Make invocation available if necessary.
    					oldProxy = AopContext.setCurrentProxy(proxy);
    					setProxyContext = true;
    				}
    				// May be null. Get as late as possible to minimize the time we
    				// "own" the target, in case it comes from a pool...
    				target = getTarget();
    				if (target != null) {
    					targetClass = target.getClass();
    				}
    				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    				Object retVal;
    				// Check whether we only have one InvokerInterceptor: that is,
    				// no real advice, but just reflective invocation of the target.
    				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    					// 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 = methodProxy.invoke(target, argsToUse);
    				}
    				else {
    					// We need to create a method invocation...
    					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    				}
    				retVal = processReturnType(proxy, target, method, retVal);
    				return retVal;
    			}
    			finally {
    				if (target != null) {
    					releaseTarget(target);
    				}
    				if (setProxyContext) {
    					// Restore old proxy.
    					AopContext.setCurrentProxy(oldProxy);
    				}
    			}
    		}
    
    		@Override
    		public boolean equals(Object other) {
    			return (this == other ||
    					(other instanceof DynamicAdvisedInterceptor &&
    							this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
    		}
    
    		/**
    		 * CGLIB uses this to drive proxy creation.
    		 */
    		@Override
    		public int hashCode() {
    			return this.advised.hashCode();
    		}
    
    		protected Object getTarget() throws Exception {
    			return this.advised.getTargetSource().getTarget();
    		}
    
    		protected void releaseTarget(Object target) throws Exception {
    			this.advised.getTargetSource().releaseTarget(target);
    		}
    	}
    

    JDK动态代理使用的ReflectiveMethodInvocation去处理,CglibAopProxy使用CglibMethodInvocation去处理,CglibMethodInvocation与ReflectiveMethodInvocation是父类与子类的关系,两者都是用同样的过程去处理bean调用时的方法。

    无论是JDK动态代理还是CGLIB动态代理,都无法对private方法进行处理,所以private修饰的方法是没有AOP机制的。对于JDK动态代理是基于接口去做代理,接口的方法都是public 修饰的;CGLIB虽然是基于类去生成代理,private与final一样,都是无法被子类继承的。

    展开全文
  • 代理模式 定义:为其他对象提供一种代理以控制对这个对象的访问 使用场景:当无法或者不想直接...代理模式的通用模式代码 /** * 抽象主题类 */ public abstract class Subject { /** * 一个普通的业务方法 */ ...

    代理模式

    定义:为其他对象提供一种代理以控制对这个对象的访问

    使用场景:当无法或者不想直接访问某个对象或访问某个对象存在困难时可以同一个代理对象来简介范根,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

    静态代理


    代理模式的通用模式代码

    /**
    * 抽象主题类
    */
    public abstract class Subject {
    	/**
    	* 一个普通的业务方法
    	*/
    	public abstract visit();
    	
    }
    

    /**
     * 实现抽象主题的真实主题类
     */
    public class RealSubject extends Subject {
        @Override
        public void visit() {
            // RealSubject中visit的具体逻辑
            System.out.println("Real subject");
        }
    }
    

    /**
     * 代理类
     */
    public class ProxySubject extends Subject {
        // 持有真实主题类的引用
        private RealSubject mSubject;
    
        public ProxySubject(RealSubject subject) {
            this.mSubject = subject;
        }
    
        @Override
        public void visit() {
            // 通过真实主题引用的对象调用真实主题中的方法
            mSubject.visit();
        }
    }
    

    /**
     * 客户类
     */
    public class Client {
        public static void main(String[] args) {
            // 构造一个真实主题对象
            RealSubject realSubject = new RealSubject();
            
            // 通过真实主题对象构造一个代理对象
            ProxySubject proxy = new ProxySubject(realSubject);
            
            // 调用代理的相关方法
            proxy.visit();
        }
    }
    

    代理模式的角色介绍

    Subject:抽象主题类

    该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。

    RealSubject:真实主题类

    该类也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑方法 而客户类则通过代理类间接地调用了真实主题中定义的方法。

    ProxySubject:代理类

    该类也称为委托类或代理类,该类持有一个真实主题类的引用,在其所实现的接口方法中调用真实主题中相应的接口方法执行,以此起到代理的作用

    Client:客户类,即使用代理类的类型

    这样看来静态代理的实现也比较简单,就是构造一个代理对象持有一个这是主题对象的引用,通过代理对象调用真实主题的方法。这样实现起来是比较容易,但是如果后面又有多个真实主题对象呢?要用静态代理模式实现的话,是不是要创建多个代理类呢?然后修改代码通过各自的代理类来调用各个真实主题的方法。这时我们就发现了静态代理模式的弊端,可维护性、可扩展性差,也就是违反了面向对象的六大原则之一的开闭原则(开放增加,关闭修改),这样一来就引出了动态代理。

    动态代理

    举个例子,比如你有一个女朋友要买鞋子,找某鞋子的品牌代理也就是代购,如果你又有一个女朋友要买包包,找某包包的品牌代理,如果你有多个女朋友,每个要买的东西都不一样,要通过不同渠道找不同的代购是不是很麻烦,可不可以找一个平台或中介,每次买东西,就找他们,由平台根据客户要买的东西,再去找具体商品的代购。例子可能不太恰当,但是个人认为已经足够解释动态代理的大概意思了,接下来是代码环节。

    /**
     * 抽象主题(买包包)接口类
     */
    public interface IBuyBag {
        // 买包包
        void buyBag();
    
    }
    
    /**
     * 真实主题类(老婆要买包包)
     */
    public class Wife implements IBuyBag {
        @Override
        public void buyBag() {
            System.out.println("给老娘买个包...");
        }
    }
    

    /**
     * 抽象主题(买鞋子)接口类
     */
    public interface IBuyBag {
        // 买鞋子
        void buyShoes();
    }
    
    /**
     * 真实主题类(女朋友要买鞋子)
     */
    public class GirlFriend implements IBuyShoes {
        @Override
        public void buyShoes() {
            System.out.println("给人家买双鞋子啦...");
        }
    }
    

    上面分别是两个抽象主题类和真实主题类,如果是静态代理,要两个创建代理对象(类), 来分别代理实现,也就是说在我们的代码运行之前代理类的class编译文件就已经存在;而动态代理则与静态代理相反,通过反射机制动态地生成代理者的对象,也就是在code阶段压根就不需要知道代理谁,代理谁将会在执行阶段决定。

    /**
     * 动态代理类
     */
    public class DynamicProxy implements InvocationHandler {
    
        // 被代理的引用
        Object obj;
    
        public DynamicProxy(Object obj) {
            this.obj = obj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 调用被代理对象的方法
            Object result = method.invoke(obj, args);
            return result;
        }
    }
    

    如上述代码所述,我们声明了一个Object的引用,该引用指向被代理类,而我们调用被代理类的具体方法在invoke方法中执行。也就是说原来由代理类所做的工作现在由InvocationHandler来处理,不需要再关心到底代理谁,下面是使用代理类的客户类。

    public class Client {
        public static void main(String[] args) {
                    // 创建wife对象
            IBuyBag wife = new Wife();
            // 构造一个动态代理
            DynamicProxy proxy1 = new DynamicProxy(wife);
            // 动态构造一个处理wife购买需求的代理者
            IBuyBag wifeProxy = (IBuyBag) Proxy.newProxyInstance(wife.getClass().getClassLoader(),
                    new Class[]{IBuyBag.class}, proxy1);
            // 代理者买包包
            wifeProxy.buyBag();
    
    
            // 创建girlfriend对象
            IBuyShoes girlfriend = new GirlFriend();
            // 构造一个动态代理
            DynamicProxy proxy2 = new DynamicProxy(girlfriend);
            // 动态构造一个处理girlfriend购买需求的代理者
            IBuyShoes girlfriendProxy = (IBuyShoes) Proxy.newProxyInstance(girlfriend.getClass().getClassLoader(),
                    new Class[]{IBuyShoes.class}, proxy2);
            // 代理者买鞋子
            girlfriendProxy.buyShoes();
        }
    }
    

    动态代理实现原理

    通过上面的例子总结一下的话,就是通过反射机制运行时动态地生成代理者对象,实现动态代理接口InvocationHandler,调用该接口需要重写其调用方法invoke,来达到调用我们真实主题类的方法。JDK的动态代理具体是如何实现的呢?下面进入源码环节,首先我们应该知道java中类的大致生命周期。

    在这里插入图片描述
    代理对象具体是如何实例化的呢?首先通过debug看一下,代理对象到底是什么东西?如下图,可以发现两个代理对象的类名信息分别以Proxy0Proxy0 和Proxy1开头的,但是有找不到相关信息。
    在这里插入图片描述
    接下来就进入源码查看环节了,先从Proxy的newProxyInstance方法开始,毕竟生成代理对象的从它开始的。
    Sdk/sources/android-28/java/lang/reflect/Proxy.java

    public class Proxy implements java.io.Serializable {
    	...
    	public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
    
            final Class<?>[] intfs = interfaces.clone();
    		// 获取代理类的类类型即Class对象
            Class<?> cl = getProxyClass0(loader, intfs);
    		// 获取构造
            final Constructor<?> cons = cl.getConstructor(constructorParams);
             ...
             	// 通过构造方法获取实例对象
            	return cons.newInstance(new Object[]{h});
    			...
        }
    	...
    }
    

    为了便于理解,只保留了与本文相关的逻辑。通过getProxyClass0()方法获取类类型即Class对象cl, 然后
    通过构造cons来获取实例对象。接下来进入getProxyClass0()方法:

    /**
         * Generate a proxy class.  Must call the checkProxyAccess method
         * to perform permission checks before calling this.
         */
        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
            // If the proxy class defined by the given loader implementing
            // the given interfaces exists, this will simply return the cached copy;
            // otherwise, it will create the proxy class via the ProxyClassFactory
            return proxyClassCache.get(loader, interfaces);
        }
    

    通过代码注释不难发现,对接口数量有限制,超过65535会抛异常。接下来会从proxyClassCache()中获取,貌似还进行了缓存,当第一次执行,还没有实例的时候,是如何创建的呢?进入其ger方法

    Sdk/sources/android-28/java/lang/reflect/WeakCache.java

    public V get(K key, P parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
    
            Object cacheKey = CacheKey.valueOf(key, refQueue);
    
            // lazily install the 2nd level valuesMap for the particular cacheKey
            ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
            if (valuesMap == null) {
                ConcurrentMap<Object, Supplier<V>> oldValuesMap
                    = map.putIfAbsent(cacheKey,
                                      valuesMap = new ConcurrentHashMap<>());
                if (oldValuesMap != null) {
                    valuesMap = oldValuesMap;
                }
            }
    
            // create subKey and retrieve the possible Supplier<V> stored by that
            // subKey from valuesMap
            // 前面都是关于缓存的相关操作,核心代码就是这一句
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            Supplier<V> supplier = valuesMap.get(subKey);
            Factory factory = null;
    
           ...
    

    如果缓存中没有,则会调用ProxyClassFactory(Proxy的内部类)的apply方法创建一个代理类。

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        // 所有jdk代理类的前缀名
        private static final String proxyClassNamePrefix = "$Proxy";
        // next number to use for generation of unique proxy class names
        // 一个无锁的long
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            // 校验类加载器是否能通过接口名称加载该类
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * 校验该类是否接口类型
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * 校验接口是否重复
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            // 代理类的包名
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            /*
             * 对于非public类,代理类的包名和接口的包名相同
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
            if (proxyPkg == null) {
                // public的代理接口,使用com.sun.proxy包名
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            /*
             * 给生成的代理类起一个名字
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            /*
             * 这个方法是真正生成字节码的地方
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                // 使用类加载器将代理类的字节码加载到JVM中
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
    

    java动态代理是利用反射机制生成一个实现代理接口的匿名类,注意只能是接口,不能是类,代码中也进行了校验,如果不是接口,会抛异常。还会进行一些其他的检查。核心就是以下三处代码

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        private static final String proxyClassNamePrefix = "$Proxy";
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    		...
    		//1
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            ...
            //2
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            ...
            //3
                // 使用类加载器将代理类的字节码加载到JVM中
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
    
    }
    

    通过注释1处代码,给生成代理类起一个名字,就对应了上文debug时,代理对象的类名信息。注释2处,通过generateProxyClass()方法生成代理类的字节码bute数组proxyClassFile,再通过defineClass0方法生成代理类的class对象,即使用类加载器将代理类的字节码加载到jvm中。这是一个native方法,后续生成的具体细节就看不到了,但是我们可以通过将字节码byte数字反编译的方式,来看生成代理类的信息。由于该类没有开源(因为这个代理是sun公司的,从包名中就可以看出),可以通过反编译工具来看。

    要想将JDK动态代理生成的class文件Proxy0Proxy0和Proxy1保存到本地,需要进行设置,网上搜到的办法是加入:System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”); 要保证你的代码在运行的时候,该行代码执行了,就会在如下目录:工程目录\com\sun\proxy路径下生成class文件了

    在这里插入图片描述
    通过反编译工具查看如下:

    package com.sun.proxy;
    
    import com.example.designpatterns.chapter_18_ProxyPattern.IBuyBag;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements IBuyBag {
      private static Method m1;
      
      private static Method m3;
      
      private static Method m2;
      
      private static Method m0;
      
      public $Proxy0(InvocationHandler paramInvocationHandler) {
        super(paramInvocationHandler);
      }
      
      public final boolean equals(Object paramObject) {
        try {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final void buyBag() {
        try {
          this.h.invoke(this, m3, null);
          return;
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final String toString() {
        try {
          return (String)this.h.invoke(this, m2, null);
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      public final int hashCode() {
        try {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        } catch (Error|RuntimeException error) {
          throw null;
        } catch (Throwable throwable) {
          throw new UndeclaredThrowableException(throwable);
        } 
      }
      
      static {
        try {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m3 = Class.forName("com.example.designpatterns.chapter_18_ProxyPattern.IBuyBag").getMethod("buyBag", new Class[0]);
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        } catch (NoSuchMethodException noSuchMethodException) {
          throw new NoSuchMethodError(noSuchMethodException.getMessage());
        } catch (ClassNotFoundException classNotFoundException) {
          throw new NoClassDefFoundError(classNotFoundException.getMessage());
        } 
      }
    }
    
    

    从代码中可以看到代理类$Proxy0继承了Proxy实现了接口。所以它可以实现被代理类的一切功能,this.h.invoke,这里的h是InvocationHandler,通过反射调用对应的方法m3. 至此动态代理的JDK实现就大致分析完了。

    关于java动态代理有两种实现方式:JDK动态代理和cglib动态代理,作为搞Android的,貌似接触前者比较多,至于后者高java接触的多,本文不做分析,有兴趣的可以点击以下链接进行查看。

    cglib动态代理、asm学习笔记

    展开全文
  • 我们在面试时候经常被问到Spring AOP的原理,大部分背一背面试题就顺口...代理模式这里可以举一个小场景来说明代理模式:小明由于喜欢小红,但是又胆小内向,不敢向小红表白。小明买好了鲜花并写好情书让他好朋...
  • 1.代理模式概念 代理模式分为两种,一种是静态代理模式,一种是动态代理模式。 静态代理模式:在程序运行之前需要写...2.动态代理的实现 动态代理实现的步骤: (1)写一个代理类SubjectHandler实现InvocationHandler...
  • 代理模式的使用总结

    万次阅读 多人点赞 2020-04-20 14:14:37
    一、代理模式 二、静态代理 (一)静态代理 (二)静态代理简单实现 三、动态代理 (一)动态代理 (二)动态代理简单实现 四、动态代理原理分析 五、InvocationHandler接口和Proxy类详解 六、JDK动态代理...
  • 代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式包含如下角色:ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。RealSubject:真实主题角色,是实现...
  • 当前一些主流的项目框架中,也有不少代理模式的身影。 代理模式中,代理类与主体类实现同样的接口,代理类持有实体类的引用,并接受客户端对代理类中实体引用的外部注入,并代理实体类的功能。 注:描述中的这种外部...
  • 简介 Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术。生活中的方方面面都可以虚拟到代码中。...代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
  • Spring代理模式的原理实现

    千次阅读 2019-09-04 20:27:26
    2、代理模式的职责:把不是目标对象该做的事情从目标对象上撇开——职责清晰; 静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和目标对象的关系在运行前就确定了。 动态代理...
  • 设计模式之代理模式和Java中代理 代理模式(Proxy Pottern)是一个使用频率很高模式,其定义如下: Provide a surrogate or placegolder for another object to contol access to it.(为其他对象提供一种代理以...
  • 本文转自Java JDK 动态代理(AOP)使用及实现原理分析 一、什么是代理代理是一种常用设计模式,其目的就是为其他对象提供一个代理以控制对某个对象访问。代理类负责为委托类预处理消息,过滤消息并转发消息,...
  • 代理模式也称为委托模式,也是极为重要设计模式之一。代理在我们日常生活中其实很常见,对于程序员来说最常接触莫过于使用代理上网,连接上代理服务器地址,就可以轻松畅游全世界网络;让同事帮忙带饭也是一种...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,073
精华内容 829
关键字:

代理模式的实现原理