精华内容
下载资源
问答
  • 详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https://blog.51cto.com/4247649/2109130 (1)什么是代理? 大道理上讲...
    详解java动态代理机制以及使用场景
    https:
    //blog.csdn.net/u011784767/article/details/78281384

    深入理解java动态代理的实现机制

    https://blog.51cto.com/4247649/2109130

    
    
    (1)什么是代理?
    
    大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。
    
    
    
    (2)什么情况下使用代理?
    
    (1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。
    
    (2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。
    
    (3)Spring的AOP机制就是采用动态代理的机制来实现切面编程。
    
    
    
    (3)静态代理和动态代理
    
    我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
    
    
    
    (4)静态代理
    
    我们先创建一个接口,遗憾的是java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口;对于动态代理代理类则不需要显示的实现被代理类所实现的接口。
    
    
    /**
     * 顶层接口
     * @author yujie.wang
     *
     */
    public interface Person {
        public void sayHello(String content, int age);
        public void sayGoodBye(boolean seeAgin, double time);
    }
    
    /**
     * 需要被代理的类 实现了一个接口Person
     * @author yujie.wang
     *
     */
    public class Student implements Person{
     
        @Override
        public void sayHello(String content, int age) {
            // TODO Auto-generated method stub
            System.out.println("student say hello" + content + " "+ age);
        }
     
        @Override
        public void sayGoodBye(boolean seeAgin, double time) {
            // TODO Auto-generated method stub
            System.out.println("student sayGoodBye " + time + " "+ seeAgin);
        }
     
    }
    
    /**
     * 静态代理,这个代理类也必须要实现和被代理类相同的Person接口
     * @author yujie.wang
     *
     */
    public class ProxyTest implements Person{
        
        private Person o;
        
        public ProxyTest(Person o){
            this.o = o;
        }
     
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问
            Student s = new Student();
            //创建代理类对象
            ProxyTest proxy = new ProxyTest(s);
            //调用代理类对象的方法
            proxy.sayHello("welcome to java", 20);
            System.out.println("******");
            //调用代理类对象的方法
            proxy.sayGoodBye(true, 100);
     
        }
     
        @Override
        public void sayHello(String content, int age) {
            // TODO Auto-generated method stub
            System.out.println("ProxyTest sayHello begin");
            //在代理类的方法中 间接访问被代理对象的方法
            o.sayHello(content, age);
            System.out.println("ProxyTest sayHello end");
        }
     
        @Override
        public void sayGoodBye(boolean seeAgin, double time) {
            // TODO Auto-generated method stub
            System.out.println("ProxyTest sayHello begin");
            //在代理类的方法中 间接访问被代理对象的方法
            o.sayGoodBye(seeAgin, time);
            System.out.println("ProxyTest sayHello end");
        }
     
    }
    
    测试代码输出:
    
    ProxyTest sayHello begin
    student say hellowelcome to java 20
    ProxyTest sayHello end
    ******
    ProxyTest sayHello begin
    student sayGoodBye 100.0 true
    ProxyTest sayHello end
    
    静态代理看起来是比较简单的,没有什么问题只不过是在代理类中引入了被代理类的对象而已。
    那么接下来我们看看动态代理。
    
    (5)动态代理
    
    我们先直接上动态代理的代码,之后再分析代码的行为,上面的Person接口和Student被代理类保持不变。
    
    
    /**
     * 动态代理,动态代理类不要显示的实现被代理类所实现的接口
     * @author yujie.wang
     *
     */
    public class MyInvocationHandler implements InvocationHandler{
        
        private Object object;
        
        public MyInvocationHandler(Object object){
            this.object = object;
        }
     
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("MyInvocationHandler invoke begin");
            System.out.println("proxy: "+ proxy.getClass().getName());
            System.out.println("method: "+ method.getName());
            for(Object o : args){
                System.out.println("arg: "+ o);
            }
            //通过反射调用 被代理类的方法
            method.invoke(object, args);
            System.out.println("MyInvocationHandler invoke end");
            return null;
        }
        
        public static void main(String [] args){
            //创建需要被代理的类
            Student s = new Student();
            //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
            //获得加载被代理类的 类加载器
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            //指明被代理类实现的接口
            Class<?>[] interfaces = s.getClass().getInterfaces();
            // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法
            MyInvocationHandler h = new MyInvocationHandler(s);
            //生成代理类
            Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);
            //通过代理类调用 被代理类的方法
            proxy.sayHello("yujie.wang", 20);
            proxy.sayGoodBye(true, 100);
            System.out.println("end");
        }
     
    }
    运行测试代码输出如下结果:
    
    MyInvocationHandler invoke begin
    proxy: com.sun.proxy.$Proxy0
    method: sayHello
    arg: yujie.wang
    arg: 20
    student say helloyujie.wang 20
    MyInvocationHandler invoke end
    MyInvocationHandler invoke begin
    proxy: com.sun.proxy.$Proxy0
    method: sayGoodBye
    arg: true
    arg: 100.0
    student sayGoodBye 100.0 true
    MyInvocationHandler invoke end
    end
    
    
    仔细分析上面的动态代理实现代码,我们看到这里涉及到java反射包下的一个接口InvocationHandler和一个类Proxy。
    
    package java.lang.reflect;
    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
    }
    这个接口只有一个invoke方法,我们在通过代理类调用被代理类的方法时,最终都会委托给这个invoke方法执行,
            //通过代理类调用 被代理类的方法
            proxy.sayHello("yujie.wang", 20);
            proxy.sayGoodBye(true, 100);
    
    所以我们就可以在这个invoke方法中对被代理类进行增强或做一些其他操作。
    Proxy类的public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法内部通过拼接字节码的方式来创建代理类,后面我会反编译出它所创建的代理类看看内容。
    
    我们看这个方法的三个参数:
    
    ClassLoader loader:指定一个动态加载代理类的类加载器
    
    Class<?>[] interfaces:指明被代理类实现的接口,之后我们通过拼接字节码生成的类才能知道调用哪些方法。
    
    InvocationHandler h:这是一个方法委托类,我们通过代理调用被代理类的方法时,就可以将方法名和方法参数都委托给这个委托类。
    
    你看我们现在有了类加载器、类实现的接口、要调用方法的方法名和参数,那么我们就可以做很多事情了。
    
    (6)反编译Proxy.newProxyInstance所创建的代理类
    
    //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    
    我们在代码中加入上述代码,代码就会保存生成的代理类,名称为$Proxy0.class
    
    
    
    通过jd-gui反编译代码如下,其中注释是我加上去的:
    
    
    package com.sun.proxy;
     
    import com.yujie.proxy.dynamic.Person;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    /**
    *代理类也实现了Person接口,看起来和静态代理的方式也会一样的 
    *同时代理类也继承了Proxy类
    */ 
    public final class $Proxy0 extends Proxy implements Person{
      private static Method m4;
      private static Method m1;
      private static Method m0;
      private static Method m3;
      private static Method m2;
      
      public $Proxy0(InvocationHandler paramInvocationHandler)
        throws 
      {
        super(paramInvocationHandler);
      }
       //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
      public final void sayGoodBye(boolean paramBoolean, double paramDouble)
        throws 
      {
        try
        {
        // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
        // m4为代理类通过反射获得的Method
          this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) });
          return;
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final boolean equals(Object paramObject)
        throws 
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final int hashCode()
        throws 
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
      public final void sayHello(String paramString, int paramInt)
        throws 
      {
        try
        {
          // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
          // m4为代理类通过反射获得的Method
          this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) });
          return;
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String toString()
        throws 
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      static
      {
        try
        {//代理类通过反射 获得的接口方法Method
          m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye", new Class[] { Boolean.TYPE, Double.TYPE });
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          //代理类通过反射 获得的接口方法Method
          m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String"), Integer.TYPE });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    }
    
    总结一下:
    jdk的代理让我们在不直接访问某些对象的情况下,通过代理机制也可以访问被代理对象的方法,这种技术可以应用在很多地方比如RPC框架,Spring AOP机制,但是我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重新那些方法。这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。

     

    转载于:https://www.cnblogs.com/kelelipeng/p/11394641.html

    展开全文
  • 说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再给公司新同事...

    说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再给公司新同事做技术培训时有同学就对动态代理产生了疑问,我这里梳理一遍一并记录一下,方便大家查看对自己也是加深记忆。

    (1)什么是代理?

    大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。

    (2)什么情况下使用代理?

    • (1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。

    • (2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。

    • (3)Spring的AOP机制就是采用动态代理的机制来实现切面编程。

    (3)静态代理和动态代理

    我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。

    (4)静态代理

    我们先创建一个接口,遗憾的是java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口;对于动态代理代理类则不需要显示的实现被代理类所实现的接口。

    顶层接口

    /**
     * 顶层接口
     * @author ss
     *
     */
    public interface Person {
    	public void sayHello(String content, int age);
    	public void sayGoodBye(boolean seeAgin, double time);
    }
    

    需要被代理的类 实现了一个接口Person

    /**
     * 需要被代理的类 实现了一个接口Person
     * @author ss
     *
     */
    public class Student implements Person{
     
    	@Override
    	public void sayHello(String content, int age) {
    		// TODO Auto-generated method stub
    		System.out.println("student say hello" + content + " "+ age);
    	}
     
    	@Override
    	public void sayGoodBye(boolean seeAgin, double time) {
    		// TODO Auto-generated method stub
    		System.out.println("student sayGoodBye " + time + " "+ seeAgin);
    	}
     
    }
    

    静态代理,这个代理类也必须要实现和被代理类相同的Person接口

    /**
     * 静态代理,这个代理类也必须要实现和被代理类相同的Person接口
     * @author ss
     */
    public class ProxyTest implements Person{
    	
    	private Person o;
    	
    	public ProxyTest(Person o){
    		this.o = o;
    	}
     
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		//s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问
    		Student s = new Student();
    		//创建代理类对象
    		ProxyTest proxy = new ProxyTest(s);
    		//调用代理类对象的方法
    		proxy.sayHello("welcome to java", 20);
    		System.out.println("******");
    		//调用代理类对象的方法
    		proxy.sayGoodBye(true, 100);
     
    	}
     
    	@Override
    	public void sayHello(String content, int age) {
    		// TODO Auto-generated method stub
    		System.out.println("ProxyTest sayHello begin");
    		//在代理类的方法中 间接访问被代理对象的方法
    		o.sayHello(content, age);
    		System.out.println("ProxyTest sayHello end");
    	}
     
    	@Override
    	public void sayGoodBye(boolean seeAgin, double time) {
    		// TODO Auto-generated method stub
    		System.out.println("ProxyTest sayHello begin");
    		//在代理类的方法中 间接访问被代理对象的方法
    		o.sayGoodBye(seeAgin, time);
    		System.out.println("ProxyTest sayHello end");
    	}
     
    }
    

    测试代码输出:

    ProxyTest sayHello begin
    student say hellowelcome to java 20
    ProxyTest sayHello end
    ******
    ProxyTest sayHello begin
    student sayGoodBye 100.0 true
    ProxyTest sayHello end
    

    静态代理看起来是比较简单的,没有什么问题只不过是在代理类中引入了被代理类的对象而已。
    那么接下来我们看看动态代理。

    (5)动态代理

    我们先直接上动态代理的代码,之后再分析代码的行为,上面的Person接口和Student被代理类保持不变。

    /**
     * 动态代理,动态代理类不要显示的实现被代理类所实现的接口
     * @author ss
     *
     */
    public class MyInvocationHandler implements InvocationHandler{
    	
    	private Object object;
    	
    	public MyInvocationHandler(Object object){
    		this.object = object;
    	}
     
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("MyInvocationHandler invoke begin");
    		System.out.println("proxy: "+ proxy.getClass().getName());
    		System.out.println("method: "+ method.getName());
    		for(Object o : args){
    			System.out.println("arg: "+ o);
    		}
    		//通过反射调用 被代理类的方法
    		method.invoke(object, args);
    		System.out.println("MyInvocationHandler invoke end");
    		return null;
    	}
    	
    	public static void main(String [] args){
    		//创建需要被代理的类
    		Student s = new Student();
    		//这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
    		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    		//获得加载被代理类的 类加载器
    		ClassLoader loader = Thread.currentThread().getContextClassLoader();
    		//指明被代理类实现的接口
    		Class<?>[] interfaces = s.getClass().getInterfaces();
    		// 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法
    		MyInvocationHandler h = new MyInvocationHandler(s);
    		//生成代理类
    		Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);
    		//通过代理类调用 被代理类的方法
    		proxy.sayHello("yujie.wang", 20);
    		proxy.sayGoodBye(true, 100);
    		System.out.println("end");
    	}
     
    }
    

    运行测试代码输出如下结果:

    MyInvocationHandler invoke begin
    proxy: com.sun.proxy.$Proxy0
    method: sayHello
    arg: yujie.wang
    arg: 20
    student say helloyujie.wang 20
    MyInvocationHandler invoke end
    MyInvocationHandler invoke begin
    proxy: com.sun.proxy.$Proxy0
    method: sayGoodBye
    arg: true
    arg: 100.0
    student sayGoodBye 100.0 true
    MyInvocationHandler invoke end
    end
    

    仔细分析上面的动态代理实现代码,我们看到这里涉及到java反射包下的一个接口InvocationHandler和一个类Proxy。

    package java.lang.reflect;
    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
    	throws Throwable;
    }
    

    所以我们就可以在这个invoke方法中对被代理类进行增强或做一些其他操作。
    Proxy类的public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法内部通过拼接字节码的方式来创建代理类,后面我会反编译出它所创建的代理类看看内容。

    我们看这个方法的三个参数:

    ClassLoader loader:指定一个动态加载代理类的类加载器

    Class<?>[] interfaces:指明被代理类实现的接口,之后我们通过拼接字节码生成的类才能知道调用哪些方法。

    InvocationHandler h:这是一个方法委托类,我们通过代理调用被代理类的方法时,就可以将方法名和方法参数都委托给这个委托类。

    你看我们现在有了类加载器、类实现的接口、要调用方法的方法名和参数,那么我们就可以做很多事情了。

    (6)反编译Proxy.newProxyInstance所创建的代理类

    //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
    System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”,“true”);

    我们在代码中加入上述代码,代码就会保存生成的代理类,名称为$Proxy0.class
    在这里插入图片描述

    通过jd-gui反编译代码如下,其中注释是我加上去的:

    package com.sun.proxy;
     
    import com.yujie.proxy.dynamic.Person;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    /**
    *代理类也实现了Person接口,看起来和静态代理的方式也会一样的 
    *同时代理类也继承了Proxy类
    */ 
    public final class $Proxy0 extends Proxy implements Person{
      private static Method m4;
      private static Method m1;
      private static Method m0;
      private static Method m3;
      private static Method m2;
      
      public $Proxy0(InvocationHandler paramInvocationHandler)
        throws 
      {
        super(paramInvocationHandler);
      }
       //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
      public final void sayGoodBye(boolean paramBoolean, double paramDouble)
        throws 
      {
        try
        {
    	// 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
    	// m4为代理类通过反射获得的Method
          this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) });
          return;
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final boolean equals(Object paramObject)
        throws 
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final int hashCode()
        throws 
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
      public final void sayHello(String paramString, int paramInt)
        throws 
      {
        try
        {
    	  // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
    	  // m4为代理类通过反射获得的Method
          this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) });
          return;
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      public final String toString()
        throws 
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      
      static
      {
        try
        {//代理类通过反射 获得的接口方法Method
          m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye", new Class[] { Boolean.TYPE, Double.TYPE });
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    	  //代理类通过反射 获得的接口方法Method
          m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String"), Integer.TYPE });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    }
    

    总结一下:

    jdk的代理让我们在不直接访问某些对象的情况下,通过代理机制也可以访问被代理对象的方法,这种技术可以应用在很多地方比如RPC框架,Spring AOP机制,但是我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重新那些方法。这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。

    展开全文
  • 说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再给公司新同事...

    说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再给公司新同事做技术培训时有同学就对动态代理产生了疑问,我这里梳理一遍一并记录一下,方便大家查看对自己也是加深记忆。

    (1)什么是代理?

    大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。


    (2)什么情况下使用代理?

    (1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑,这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。

    (2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。

    (3)Spring的AOP机制就是采用动态代理的机制来实现切面编程。


    (3)静态代理和动态代理

    我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。


    (4)静态代理

    我们先创建一个接口,遗憾的是java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口;对于动态代理代理类则不需要显示的实现被代理类所实现的接口。

    [java] view plain copy
    1. /** 
    2.  * 顶层接口 
    3.  * @author yujie.wang 
    4.  * 
    5.  */  
    6. public interface Person {  
    7.     public void sayHello(String content, int age);  
    8.     public void sayGoodBye(boolean seeAgin, double time);  
    9. }  

    [java] view plain copy
    1. /** 
    2.  * 需要被代理的类 实现了一个接口Person 
    3.  * @author yujie.wang 
    4.  * 
    5.  */  
    6. public class Student implements Person{  
    7.   
    8.     @Override  
    9.     public void sayHello(String content, int age) {  
    10.         // TODO Auto-generated method stub  
    11.         System.out.println("student say hello" + content + " "+ age);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void sayGoodBye(boolean seeAgin, double time) {  
    16.         // TODO Auto-generated method stub  
    17.         System.out.println("student sayGoodBye " + time + " "+ seeAgin);  
    18.     }  
    19.   
    20. }  

    [java] view plain copy
    1. /** 
    2.  * 静态代理,这个代理类也必须要实现和被代理类相同的Person接口 
    3.  * @author yujie.wang 
    4.  * 
    5.  */  
    6. public class ProxyTest implements Person{  
    7.       
    8.     private Person o;  
    9.       
    10.     public ProxyTest(Person o){  
    11.         this.o = o;  
    12.     }  
    13.   
    14.     public static void main(String[] args) {  
    15.         // TODO Auto-generated method stub  
    16.         //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问  
    17.         Student s = new Student();  
    18.         //创建代理类对象  
    19.         ProxyTest proxy = new ProxyTest(s);  
    20.         //调用代理类对象的方法  
    21.         proxy.sayHello("welcome to java"20);  
    22.         System.out.println("******");  
    23.         //调用代理类对象的方法  
    24.         proxy.sayGoodBye(true100);  
    25.   
    26.     }  
    27.   
    28.     @Override  
    29.     public void sayHello(String content, int age) {  
    30.         // TODO Auto-generated method stub  
    31.         System.out.println("ProxyTest sayHello begin");  
    32.         //在代理类的方法中 间接访问被代理对象的方法  
    33.         o.sayHello(content, age);  
    34.         System.out.println("ProxyTest sayHello end");  
    35.     }  
    36.   
    37.     @Override  
    38.     public void sayGoodBye(boolean seeAgin, double time) {  
    39.         // TODO Auto-generated method stub  
    40.         System.out.println("ProxyTest sayHello begin");  
    41.         //在代理类的方法中 间接访问被代理对象的方法  
    42.         o.sayGoodBye(seeAgin, time);  
    43.         System.out.println("ProxyTest sayHello end");  
    44.     }  
    45.   
    46. }  

    测试代码输出:

    [java] view plain copy
    1. ProxyTest sayHello begin  
    2. student say hellowelcome to java 20  
    3. ProxyTest sayHello end  
    4. ******  
    5. ProxyTest sayHello begin  
    6. student sayGoodBye 100.0 true  
    7. ProxyTest sayHello end  

    静态代理看起来是比较简单的,没有什么问题只不过是在代理类中引入了被代理类的对象而已。

    那么接下来我们看看动态代理。

    (5)动态代理

    我们先直接上动态代理的代码,之后再分析代码的行为,上面的Person接口和Student被代理类保持不变。

    [java] view plain copy
    1. /** 
    2.  * 动态代理,动态代理类不要显示的实现被代理类所实现的接口 
    3.  * @author yujie.wang 
    4.  * 
    5.  */  
    6. public class MyInvocationHandler implements InvocationHandler{  
    7.       
    8.     private Object object;  
    9.       
    10.     public MyInvocationHandler(Object object){  
    11.         this.object = object;  
    12.     }  
    13.   
    14.     @Override  
    15.     public Object invoke(Object proxy, Method method, Object[] args)  
    16.             throws Throwable {  
    17.         // TODO Auto-generated method stub  
    18.         System.out.println("MyInvocationHandler invoke begin");  
    19.         System.out.println("proxy: "+ proxy.getClass().getName());  
    20.         System.out.println("method: "+ method.getName());  
    21.         for(Object o : args){  
    22.             System.out.println("arg: "+ o);  
    23.         }  
    24.         //通过反射调用 被代理类的方法  
    25.         method.invoke(object, args);  
    26.         System.out.println("MyInvocationHandler invoke end");  
    27.         return null;  
    28.     }  
    29.       
    30.     public static void main(String [] args){  
    31.         //创建需要被代理的类  
    32.         Student s = new Student();  
    33.         //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常  
    34.         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");  
    35.         //获得加载被代理类的 类加载器  
    36.         ClassLoader loader = Thread.currentThread().getContextClassLoader();  
    37.         //指明被代理类实现的接口  
    38.         Class<?>[] interfaces = s.getClass().getInterfaces();  
    39.         // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法  
    40.         MyInvocationHandler h = new MyInvocationHandler(s);  
    41.         //生成代理类  
    42.         Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);  
    43.         //通过代理类调用 被代理类的方法  
    44.         proxy.sayHello("yujie.wang"20);  
    45.         proxy.sayGoodBye(true100);  
    46.         System.out.println("end");  
    47.     }  
    48.   
    49. }  
    运行测试代码输出如下结果:

    [java] view plain copy
    1. MyInvocationHandler invoke begin  
    2. proxy: com.sun.proxy.$Proxy0  
    3. method: sayHello  
    4. arg: yujie.wang  
    5. arg: 20  
    6. student say helloyujie.wang 20  
    7. MyInvocationHandler invoke end  
    8. MyInvocationHandler invoke begin  
    9. proxy: com.sun.proxy.$Proxy0  
    10. method: sayGoodBye  
    11. arg: true  
    12. arg: 100.0  
    13. student sayGoodBye 100.0 true  
    14. MyInvocationHandler invoke end  
    15. end  


    仔细分析上面的动态代理实现代码,我们看到这里涉及到java反射包下的一个接口InvocationHandler和一个类Proxy。

    [java] view plain copy
    1. package java.lang.reflect;  
    2. public interface InvocationHandler {  
    3.     public Object invoke(Object proxy, Method method, Object[] args)  
    4.     throws Throwable;  
    5. }  
    这个接口只有一个invoke方法,我们在通过代理类调用被代理类的方法时,最终都会委托给这个invoke方法执行,
    [java] view plain copy
    1. //通过代理类调用 被代理类的方法  
    2. proxy.sayHello("yujie.wang"20);  
    3. proxy.sayGoodBye(true100);  

    所以我们就可以在这个invoke方法中对被代理类进行增强或做一些其他操作。

    Proxy类的public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法内部通过拼接字节码的方式来创建代理类,后面我会反编译出它所创建的代理类看看内容。

    我们看这个方法的三个参数:

    ClassLoader loader:指定一个动态加载代理类的类加载器

    Class<?>[] interfaces:指明被代理类实现的接口,之后我们通过拼接字节码生成的类才能知道调用哪些方法。

    InvocationHandler h:这是一个方法委托类,我们通过代理调用被代理类的方法时,就可以将方法名和方法参数都委托给这个委托类。

    你看我们现在有了类加载器、类实现的接口、要调用方法的方法名和参数,那么我们就可以做很多事情了。

    (6)反编译Proxy.newProxyInstance所创建的代理类

    //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

    我们在代码中加入上述代码,代码就会保存生成的代理类,名称为$Proxy0.class


    通过jd-gui反编译代码如下,其中注释是我加上去的:

    [java] view plain copy
    1. package com.sun.proxy;  
    2.   
    3. import com.yujie.proxy.dynamic.Person;  
    4. import java.lang.reflect.InvocationHandler;  
    5. import java.lang.reflect.Method;  
    6. import java.lang.reflect.Proxy;  
    7. import java.lang.reflect.UndeclaredThrowableException;  
    8. /** 
    9. *代理类也实现了Person接口,看起来和静态代理的方式也会一样的  
    10. *同时代理类也继承了Proxy类 
    11. */   
    12. public final class $Proxy0 extends Proxy implements Person{  
    13.   private static Method m4;  
    14.   private static Method m1;  
    15.   private static Method m0;  
    16.   private static Method m3;  
    17.   private static Method m2;  
    18.     
    19.   public $Proxy0(InvocationHandler paramInvocationHandler)  
    20.     throws   
    21.   {  
    22.     super(paramInvocationHandler);  
    23.   }  
    24.    //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用   
    25.   public final void sayGoodBye(boolean paramBoolean, double paramDouble)  
    26.     throws   
    27.   {  
    28.     try  
    29.     {  
    30.     // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法  
    31.     // m4为代理类通过反射获得的Method  
    32.       this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) });  
    33.       return;  
    34.     }  
    35.     catch (Error|RuntimeException localError)  
    36.     {  
    37.       throw localError;  
    38.     }  
    39.     catch (Throwable localThrowable)  
    40.     {  
    41.       throw new UndeclaredThrowableException(localThrowable);  
    42.     }  
    43.   }  
    44.     
    45.   public final boolean equals(Object paramObject)  
    46.     throws   
    47.   {  
    48.     try  
    49.     {  
    50.       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();  
    51.     }  
    52.     catch (Error|RuntimeException localError)  
    53.     {  
    54.       throw localError;  
    55.     }  
    56.     catch (Throwable localThrowable)  
    57.     {  
    58.       throw new UndeclaredThrowableException(localThrowable);  
    59.     }  
    60.   }  
    61.     
    62.   public final int hashCode()  
    63.     throws   
    64.   {  
    65.     try  
    66.     {  
    67.       return ((Integer)this.h.invoke(this, m0, null)).intValue();  
    68.     }  
    69.     catch (Error|RuntimeException localError)  
    70.     {  
    71.       throw localError;  
    72.     }  
    73.     catch (Throwable localThrowable)  
    74.     {  
    75.       throw new UndeclaredThrowableException(localThrowable);  
    76.     }  
    77.   }  
    78.   //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用   
    79.   public final void sayHello(String paramString, int paramInt)  
    80.     throws   
    81.   {  
    82.     try  
    83.     {  
    84.       // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法  
    85.       // m4为代理类通过反射获得的Method  
    86.       this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) });  
    87.       return;  
    88.     }  
    89.     catch (Error|RuntimeException localError)  
    90.     {  
    91.       throw localError;  
    92.     }  
    93.     catch (Throwable localThrowable)  
    94.     {  
    95.       throw new UndeclaredThrowableException(localThrowable);  
    96.     }  
    97.   }  
    98.     
    99.   public final String toString()  
    100.     throws   
    101.   {  
    102.     try  
    103.     {  
    104.       return (String)this.h.invoke(this, m2, null);  
    105.     }  
    106.     catch (Error|RuntimeException localError)  
    107.     {  
    108.       throw localError;  
    109.     }  
    110.     catch (Throwable localThrowable)  
    111.     {  
    112.       throw new UndeclaredThrowableException(localThrowable);  
    113.     }  
    114.   }  
    115.     
    116.   static  
    117.   {  
    118.     try  
    119.     {//代理类通过反射 获得的接口方法Method  
    120.       m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye"new Class[] { Boolean.TYPE, Double.TYPE });  
    121.       m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] { Class.forName("java.lang.Object") });  
    122.       m0 = Class.forName("java.lang.Object").getMethod("hashCode"new Class[0]);  
    123.       //代理类通过反射 获得的接口方法Method  
    124.       m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello"new Class[] { Class.forName("java.lang.String"), Integer.TYPE });  
    125.       m2 = Class.forName("java.lang.Object").getMethod("toString"new Class[0]);  
    126.       return;  
    127.     }  
    128.     catch (NoSuchMethodException localNoSuchMethodException)  
    129.     {  
    130.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());  
    131.     }  
    132.     catch (ClassNotFoundException localClassNotFoundException)  
    133.     {  
    134.       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());  
    135.     }  
    136.   }  
    137. }  

    总结一下:

    jdk的代理让我们在不直接访问某些对象的情况下,通过代理机制也可以访问被代理对象的方法,这种技术可以应用在很多地方比如RPC框架,Spring AOP机制,但是我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重新那些方法。这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。

     转自:https://blog.csdn.net/u011784767/article/details/78281384
    展开全文
  • 动态代理模式

    2020-04-05 23:40:29
    自我修养之动态代理模式 什么是代理? 代理:顾名思义就是代为处理的意思,在日常生活中,代理无处不在,比如说代购,代课等等 如何去使用代理以及分析动态代理是如何实现的,下面我将从静态代理开始分析: 场景: ...

    自我修养之动态代理模式

    什么是代理?

    代理:顾名思义就是代为处理的意思,在日常生活中,代理无处不在,比如说代购,代课等等
    

    如何去使用代理以及分析动态代理是如何实现的,下面我将从静态代理开始分析:

    场景:
    	陈老师是教语文的,有一天陈老师生病了,没办法就请了隔壁老王去代课
    

    首先来看下代理有哪些角色

    在这里插入图片描述

    Subject 是顶层接口,RealSubject 是真实对象(被代理对象),Proxy Subject是代理对象,代

    理对象持有被代理对象的引用,客户端调用代理对象方法,同时也调用被代理对象的方

    法,但是在代理对象前后增加一些处理。

    静态代理

    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:24 2020/4/5 0005
     * @ Description:顶层接口
     */
    public interface Teacher {
        //教书
        public void doTeach();
        
    }
    
    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:24 2020/4/5 0005
     * @ Description:陈老师上课
     */
    public class ChenTeacher implements Teacher {
        @Override
        public void doTeach() {
            System.out.println("上课。。。");
        }
    }
    

    由于陈老师生病了,需要找隔壁老王代理。

    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:27 2020/4/5 0005
     * @ Description:隔壁老王去代课
     */
    public class GeBiLaoWangTeacher implements Teacher {
        //拿到目标对象的引用
        private Teacher targetTeacher;
    
        public GeBiLaoWangTeacher(Teacher targetTeacher) {
            this.targetTeacher = targetTeacher;
        }
    
        //代理老师代课
        @Override
        public void doTeach() {
            System.out.println("课前 大家好  我是代理老师 我叫隔壁老王");
            targetTeacher.doTeach();
            System.out.println("同学们下课了");
        }
    }
    

    客户端调用

    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:31 2020/4/5 0005
     * @ Description:客户端调用
     */
    public class StaticProxyClient {
    
        public static void main(String[] args) {
            //拿到目标对象
            Teacher targetTeacher = new ChenTeacher();
            //创建代理对象
            Teacher proxyTeacher = new GeBiLaoWangTeacher(targetTeacher);
            //代理上课
            proxyTeacher.doTeach();
    
        }
    }
    

    测试结果如下:

    在这里插入图片描述

    看到这里,其实我们可以想到一个问题,就是如果有多个目标对象,对目标对象进行代理就需要不断的创建代理类,这样系统中的类就会太多不易维护,那如何去解决这个问题呢?接下来引入动态代理

    动态代理

    什么是代理代理?

    动态代理是java在运行时通过字节码重组技术动态生成class类的技术
    

    目前有两种实现动态代理的方式

    • JDK 特点:目标类需要实现一个接口,并且代理类需要实现InvocationHandler接口
    • Cglib 原理:是通过继承的方式进行实现的

    我们主要讨论使用JDK的方式实现动态代理。为了让代理类可以代理所有的目标对象,我们在代理类中的引用则需要设置为Object类型,如下:

    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:42 2020/4/5 0005
     * @ Description:代理类
     * @ Modified By:
     */
    public class DynamicProxy implements InvocationHandler {
        private Object target;
        public Object getProxyInstance(Object target){
            this.target = target;
            Class<?>[] interfaces = target.getClass().getInterfaces();
            //参数一 传入当前类的类加载器
            //参数二 目标类使用的接口(可以是多个)
            //参数三 使用了InvocationHandler 也就是当前类对象
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //执行目标对象方法前
            before();
            Object result = method.invoke(target, args);
            //执行目标对象方法后
            after();
            return result;
        }
    
        private void after() {
            System.out.println("after...");
        }
    
        private void before() {
            System.out.println("before...");
        }
    }
    

    客户端进行测试:

    /**
     * @ Author     :kwj.
     * @ Date       :Created in 22:51 2020/4/5 0005
     * @ Description:客户端测试类
     * @ Modified By:
     */
    public class DynamicProxyTest {
    
        public static void main(String[] args) {
            DynamicProxy teacherProxy = new DynamicProxy();
            Teacher proxyInstance = (Teacher) teacherProxy.getProxyInstance(new ChenTeacher());
            proxyInstance.doTeach();
        }
    
    }
    

    在这里插入图片描述

    ok,到这一步为止,动态代理就算讲完了,可能小伙伴就会有很好奇,这个代理类到底是个什么东西,长什么样子呢?下面我们一探究竟:

    我们通过从内存中的对象字节码通过文件流输出到一个新的 class 文件(也就是代理类)

    public class DynamicProxyTest {
    
        public static void main(String[] args) throws IOException {
            DynamicProxy teacherProxy = new DynamicProxy();
            Teacher proxyInstance = (Teacher) teacherProxy.getProxyInstance(new ChenTeacher());
            proxyInstance.doTeach();
    
            //生成代理类的class文件
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Teacher.class});
            FileOutputStream fos = new FileOutputStream("E:\\$Proxy0.class");
            fos.write(bytes);
            fos.flush();
            fos.close();
        }
    
    }
    

    在E盘下找到这个$Proxy0.class文件,直接拖到idea中进行反编译

    public final class $Proxy0 extends Proxy implements Teacher {
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final void doTeach() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m3 = Class.forName("com.wukong.pattern.代理模式.静态代理.Teacher").getMethod("doTeach");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    

    可以看到代理类去继承了Proxy并实现了目标类的接口,对目标类中的doTeach进行了重写从而达到代理的目的。

    结合Mybatis来看动态代理在框架中的应用

    已SqlSession.getMapper(xxx.class)为例,我们知道这里是去生成一个接口的代理类,那么内部到底是如何出来处理的呢?

    首先是调用DefaultSqlSession#getMapper,如下:

      @Override
      public <T> T getMapper(Class<T> type) {
        return configuration.<T>getMapper(type, this);
      }
    

    接下来就是到Configuration#getMapper方法

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
      }
    

    MapperRegistry

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
          throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
          return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
          throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
      }
    

    最终就调用到了MapperProxyFactory,顾名思义就是用来生产MapperProxy(即Mapper的代理类)

    public class MapperProxyFactory<T> {
    
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
    
      public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
      }
    
      public Class<T> getMapperInterface() {
        return mapperInterface;
      }
    
      public Map<Method, MapperMethod> getMethodCache() {
        return methodCache;
      }
    
      @SuppressWarnings("unchecked")
      protected T newInstance(MapperProxy<T> mapperProxy) {
          //标注:mapperProxy就是我们的代理类,那么既然是JDK代理,肯定会实现InvocationHandler
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      }
    
      public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    }
    

    如标注部分说明MapperProxy果然实现了InvocationHandler接口

    在这里插入图片描述

    这样小伙伴们想对动态代理认识是不是又多了一份兴趣呢,欢迎批评指教哦

    展开全文
  • 如今,代理ip在我们身边的应用越来越多,那么大家知道动态ip代理软件的使用场景有哪些吗?下面就跟随小编一起来了解下吧: 1、媒体: 可在今日头条等媒体平台申请自己的公众号,通过自己熟悉的经验或内容赚钱,各...
  • 目录标题代理模式介绍定义为什么使用代理模式代理模式实现原理代理模式应用场景代理模式创建的方式静态代理基于接口实现接口继承方式实现动态代理JDK动态代理CGLIB动态代理 代理模式介绍 定义 代理模式的定义:代理...
  • 装饰者模式: 定义 在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能) 类型 结构型 ...适用场景 ...扩展一个类的功能或者给一个类添加附加职责 ...代理模式是常用...
  • 代理模式使用场景 代理模式的定义:什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息...
  • Java代理模式动态代理详解

    千次阅读 2020-03-21 11:15:52
    Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP、Java注解的获取、日志、用户鉴权等。本篇文章带大家了解一下代理模式、静态代理以及基于JDK原生动态代理代理模式 无论学习静态代理或动态...
  • 说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再给公司新同事...
  • 时,动态代理模式,最适合你。 特别提示: 1、本案例主要是阐述动态代理的原理,及其模拟过程,可以提示对动态代理的理解和掌握。 2、JDK6以上版本,系统自带的有动态代理类Proxy,我们可以直接用,我们只需要专注于...
  • Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP、Java注解的获取、日志、用户鉴权等。本篇文章带大家了解一下代理模式、静态代理以及基于JDK原生动态代理代理模式无论学习静态代理或动态代理...
  • 文章目录一、代理模式定义二、代理模式的结构和说明三、代理模式的分类四、代理模式示例...使用步骤CGLIB动态代理示例CGLIB动态代理实现原理CGLIB动态代理注意事项六、三种代理方式的对比七、代理模式的应用场景及案例...
  • 代理模式 (1)什么是代理? 代理是一种常用的设计模式,主要作用是为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以再客户端和目标对象之间起到中介...
  • Java动态代理模式

    2015-04-26 01:22:32
    代理模式有很多种,包括静态代理,保护代理,远程代理,动态代理等等,每一种都有特定的使用场景。本文主要介绍Java中的动态代理。   一、静态代理和动态代理的区别  首先给出静态代理和动态代理的定义:  ...
  • 1. 关于代理模式的简单介绍,和...2. 代理模式动态代理使用场景  详解java动态代理机制以及使用场景(一)     更多动态代理相关的内容,可以参考另一篇文章:Android AOP三剑客学习:APT, AspectJ, Javas...
  • 本文主要是展示java动态代理使用方式和应用场景 主要分为以下4个部分: 1.为什么要使用java动态代理 2.如何使用java动态代理 3.框架中java动态代理的应用 4.java动态代理的基本原理 1.为何要使用动态代理 ...
  • 使用动态代理解决网站的字符集编码问题 设计模式: 什么是设计模式,简单的来说,就是在软件开发当中遇到的一些相似问题,将问题的解决方式抽取出的模型(开发套路 ),来解决软件开发当中遇到的问题。 单列,工厂,...
  • 本节我们一起来探讨一下动态代理原理以及其使用场景代理模式这里可以举一个小场景来说明代理模式:小明由于喜欢小红,但是又胆小内向,不敢向小红表白。小明买好了鲜花并写好情书让他的好朋...
  • 代理模式动态代理

    2021-05-14 09:18:12
    一、使用jdk提供的动态代理场景 特点:当被代理对象是接口并且有对应的实现类(子类)的时候,可以采用该种代理方式。 spring环境下的代码实现 首先是父接口 package my.reflect; import org.springframework....
  • 文章目录代理类示例代理模式的定义代理模式的应用代理模式的优点代理模式使用场景代理模式的扩展普通代理强制代理代理是有个性的动态代理 代理类示例 以前很喜欢打游戏,和队友们一起打怪升级,那么通过一段简单...
  • 设计模式02-动态代理模式

    千次阅读 2017-10-28 13:45:58
    上一篇博客,我们以小明买雪碧为例介绍了代理模式(静态代理)的使用场景和代码实现 静态代理模式介绍现在再来考虑以下假设的生活场景小明 从楼下书店下单买书,书店再向印刷厂下单,积100分; 从楼下五金店下单买...
  • 代理模式使用场景4. 代理模式在Java中的应用5. 拓展一:普通代理与强制代理6. 拓展二:代理模式与装饰者模式的异同四、结语 一、代理模式简介 1. 什么是代理模式 代理模式(Proxy Pattern) 也叫做委托模式,属于...
  • 代理模式的作用及使用场景 使用代理模式的根本目的在于:如何在不直接操作对象的情况下,对此对象进行访问? 常用的场合包括:1)延迟加载;2)在调用实际对象的方法前后加入某些业务逻辑(作用有点像spring的AOP) ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 467
精华内容 186
关键字:

动态代理模式使用场景