zoukankan      html  css  js  c++  java
  • Java 代理

    当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象。

    按照代理对象的创建时期不同,可以分为两种:

    静态代理:事先写好代理对象类,在程序发布前就已经存在了;

    动态代理:应用程序发布后,通过动态创建代理对象。

    静态代理其实就是一个典型的代理模式实现,在代理类中包装一个被代理对象,然后影响被代理对象的行为,比较简单,代码就不放了。

    其中动态代理又可分为:JDK动态代理和CGLIB代理。

    1.JDK动态代理

    此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

    代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。

    JDK动态代理只能针对实现了接口的类生成代理。

    2.CGLIB代理

    CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,

    主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

    JDK动态代理和CGLIB代理生成的区别

    JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
    CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
    因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

    PS:final 所修饰的数据具有“终态”的特征,表示“最终的”意思:

    final 修饰的类不能被继承。
    final 修饰的方法不能被子类重写。
    final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次。
    final 修饰的成员变量必须在声明的同时赋值,如果在声明的时候没有赋值,那么只有 一次赋值的机会,而且只能在构造方法中显式赋值,然后才能使用。
    final 修饰的局部变量可以只声明不赋值,然后再进行一次性的赋值。

    JDK代理:

    import java.lang.reflect.*;
    
    
    public class Main{
        public static void main(String[] args) {
            // 我们要代理的真实对象
            Subject realSubject = new RealSubject();
            // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象调用方法的
            InvocationHandler handler = new DynamicProxy(realSubject);
            /*
             * 通过Proxy的newProxyInstance方法来动态创建我们的代理对象,我们来看看其三个参数<br/>
             * 参数一:我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象<br/>
             * 参数二:我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了<br/>
             * 参数三:我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
             */
            Subject proxyInstance = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                    RealSubject.class.getInterfaces(),
                    handler);
    
            System.out.println(proxyInstance.getClass().getName());
            proxyInstance.visit();
        }
    }
    
    interface Subject {
        public void visit();
    }
    
    class RealSubject implements Subject {
    
        @Override
        public void visit() {
            System.out.println("I am 'RealSubject',I am the execution method");
        }
    
    }
    
    class DynamicProxy implements InvocationHandler {
    
        // 我们要代理的真实对象(委托对象)
        private Object subject;
    
        // 构造方法,给我们要代理的真实对象赋初值
        public DynamicProxy(Object obj){
            this.subject = obj;
        }
    
        @Override
        public Object invoke(Object object, Method method, Object[] args)
                throws Throwable {
            // 在代理真实对象操作前 我们可以添加一些自己的操作
            System.out.println("before proxy invoke");
    
            // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
            method.invoke(subject, args);
    
            // 在代理真实对象操作后 我们也可以添加一些自己的操作
            System.out.println("after proxy invoke");
            return null;
        }
    }
    com.company.$Proxy0
    before proxy invoke
    I am 'RealSubject',I am the execution method
    after proxy invoke

     CGLib代理:

    package com.company;
    
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodProxy;
    import org.springframework.cglib.proxy.MethodInterceptor;
    
    import java.lang.reflect.Method;
    
    public class Main{
        public static void main(String[] args) {
            CglibDynamicProxy cglib = new CglibDynamicProxy();
            CglibRealSubject realSubject = (CglibRealSubject) cglib.getProxyInstance(new CglibRealSubject());
            realSubject.visit();
        }
    }
    
    class CglibRealSubject{
        public void visit() {
            System.out.println("I am 'RealSubject',I am the execution method");
        }
    }
    
    class CglibDynamicProxy implements MethodInterceptor {
        private Object target;
    
        /**
         * 创建代理对象
         * @param target 被代理的对象
         * @return
         */
        public Object getProxyInstance(Object target){
            this.target = target;
            // 声明增强类实例
            Enhancer enhancer = new Enhancer();
            // 设置被代理类字节码,CGLIB根据字节码生成被代理类的子类
            enhancer.setSuperclass(this.target.getClass());
            // 设置要代理的拦截器,回调函数,即一个方法拦截   new MethodInterceptor()
            enhancer.setCallback(this);
            // 创建代理对象 实例
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                                MethodProxy proxy) throws Throwable {
            // 在代理真实对象操作前 我们可以添加一些自己的操作
            System.out.println("前置代理,增强处理");
    
            proxy.invokeSuper(obj, args);
    
            // 在代理真实对象操作后 我们也可以添加一些自己的操作
            System.out.println("后置代理,增强处理");
            return null;
        }
    }
    前置代理,增强处理
    I am 'RealSubject',I am the execution method
    后置代理,增强处理

    http://blog.csdn.net/janice0529/article/details/42884019

    http://www.cnblogs.com/binyue/p/4519652.html

    http://www.kancloud.cn/evankaka/springlearning/119667

  • 相关阅读:
    线程池中shutdown()和shutdownNow()方法的区别
    java.util.concurrent.TimeoutException: Idle timeout expired: 300000/300000 ms
    ConnectTimeout和ReadTimeout所代表的意义
    hive 查询注意问题
    java面试题之int和Integer的区别
    MySQL中KEY、PRIMARY KEY、UNIQUE KEY、INDEX 的区别
    MySQL数据库使用mysqldump导出数据详解
    C++宏定义详解
    OTL调用存储过程/函数及注意事项
    linux自定义开机启动服务和chkconfig使用方法
  • 原文地址:https://www.cnblogs.com/hongdada/p/6497422.html
Copyright © 2011-2022 走看看