• JAVA静态代理动态代理详解


    1. 代理模式

    • Proxy Pattern,又称为委托模式,为设计模式的一种

    • 为目标对象提供了一个代理,这个代理可以控制对目标对对象的访问

      • 外界不用直接访问目标对象,而是访问代理对象,由代理对象再调用目标对象
      • 代理对象中可以添加监控和审查处理

    1.1. 静态代理

    • 代理对象持有目标对象的句柄,成员变量
    • 所有调用目标对象的方法,都调用代理对象的方法
    • 对每个方法都需要静态编码
    public interface Subject{
        public void request();
    }
    
    //原对象
    class SubjectImpl implements Subject{
      public void request(){
          System.out.println("I am dealing the request.");
      }
    }
    
    //代理对象
    class StaticProxy implements Subject{
    	//实际目标对象
        private Subject subject;
        public StaticProxy(Subject subject){
            this.subject = subject;
        }
        public void request(){
            System.out.println("PreProcess");
            subject.request();
            System.out.println("PostProcess");
        }
        public static void main(String args[]){
        	//创建实际对象
            SubjectImpl subject = new SubjectImpl();
            //把实际对象封装到代理对象中
            StaticProxy p = new StaticProxy(subject);
            p.request();
        }
    }
    

    1.2. 动态代理

    • 代理处理器持有目标对象的句柄

    • 代理处理器实现InvocationHandler接口

      • 实现invoke方法
      • 所有的代理对象方法调用,都会转发到invoke方法
      • invoke的形参method,就是指代理对象方法的调用
      • 在invoke内部,可以根据method,使用目标对象不同的方法来响应请求
    
    public interface Subject{
        public void request();
    }
    
    //目标对象
    class SubjectImpl implements Subject{
      public void request(){
          System.out.println("I am dealing the request.");
      }
    }
    
    /**
     * 代理类的调用处理器,实现InvocationHandler接口,实现invoke方法
     */
    class ProxyHandler implements InvocationHandler{
        private Subject subject;
        public ProxyHandler(Subject subject){
            this.subject = subject;
        }
    
        //此函数在代理对象调用任何一个方法时都会被调用。
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
        	System.out.println(proxy.getClass().getName());
        	//定义预处理的工作,
            System.out.println("====before====");
            Object result = method.invoke(subject, args);
            System.out.println("====after====");
            return result;
        }
    }
    
    //动态代理模式类,主类
    public class DynamicProxyDemo {
        public static void main(String[] args) {
        	//1.创建目标对象
        	SubjectImpl realSubject = new SubjectImpl();
    
        	//2.创建调用处理器对象
        	ProxyHandler handler = new ProxyHandler(realSubject);
    
        	//3.动态生成代理对象
            Subject proxySubject =(Subject)Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(),SubjectImpl.class.getInterfaces(), handler);
                    //proxySubject真实类型com.sun.proxy.$Proxy0
                    //proxySubject继承Proxy类,实现Subject接口
                    //获取类加载器,获取指定代理对象的接口
    
    
            //4.代理对象调用方法
            proxySubject.request();//本次调用将自动被代理处理器的invoke方法接收
    
            System.out.println(proxySubject.getClass().getName());
            System.out.println(proxySubject.getClass().getSuperclass().getName());
        }
    }
    /*result:
    com.sun.proxy.$Proxy0
    ====before====
    I am dealing the request.
    ====after====
    com.sun.proxy.$Proxy0
    java.lang.reflect.Proxy
    */
    

    1. 动态代理对象的创建过程?

    1. 通过Proxy.newProxyInstance()动态代理生成代理对象,com.sun.proxy.$Proxy0代理类由JDK自己生成,生成一个继承Proxy和实现subject接口的代理类。

    2. 然后把得到的$Proxy0实例强制转型为Subject,并将引用赋给subject。

    3. 接着$Proxy0调用父类Proxy的构造器,为h赋值。

    4. 当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

    2. 动态代理是怎样调用invoke()方法?

    代理对象的类中接口的实现类调用了invoke方法

    ```java
    public final class $Proxy0 extends Proxy implements subject { 
    
        //....
        public final void request() {  
            try {  
                super.h.invoke(this, m3, null);  
                return;  
            } catch (Error e) {  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        } 
        //.....
    }
    ```
    

    JDK动态代理文件$Proxy0.class的生成和查看

    invoke()调用问题

    3. 代理对象

    1. 通常和目标对象实现同样的接口(可另实现其他的接口)
    2. 实现多个接口
      1. 接口的排序非常重要
      2. 当多个接口里面有方法同名,则默认以第一个接口的方法调用
    3. 根据给定的接口,由Proxy类自动生成的对象
    4. 类型 com.sun.proxy.$Proxy0,继承自java.lang.reflect.Proxy

    4.invoke方法的参数:

    public Object invoke(Object proxy, Method method, Object[] args){
        Object result = method.invoke(subject, args);
    }
    

    proxy为代理对象,method为委托对象调用他自己的方法(通过反射调用),Object[] args为代理对象调用方法时传入的参数。

    在invoke方法中调用委托对象的方法:method.invoke(subject, args);subject为委托对象

    5. 代理对象的创建方法:

    1. 创建目标对象

    2. 动态生成代理对象

      Subject proxySubject =(Subject)Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(),SubjectImpl.class.getInterfaces(), handler);
      
    3. 代理对象调用方法

  • 相关阅读:
    Qt音视频开发11-ffmpeg常用命令
    Qt音视频开发10-ffmpeg控制播放
    Qt音视频开发9-ffmpeg录像存储
    Intellij IDEA 与maven 版本不符 Unable to import maven project See logs for details: No implementation for org.apache.maven.model.path.PathTranslator was bound
    Java Map 遍历史上最全
    java new date 结果与操作系统时间相差8小时处理解决方法
    elasticsearch报错
    Pytorch-基于Transformer的情感分类
    Pytorch-LSTM+Attention文本分类
    PHP FFI调用go,居然比go还快
  • 原文地址:https://www.cnblogs.com/innndown/p/12361760.html
Copyright © 2020-2023  润新知