美文网首页
结构型-代理模式

结构型-代理模式

作者: 钉某人 | 来源:发表于2017-11-18 13:52 被阅读0次

    源码地址|https://github.com/DingMouRen/DesignPattern

    代理模式:在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。

    静态代理类

    在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。

    
    /**
     * 抽象接口
     */
    public interface Manager {
    
        void doSomething();
    }
    
    /**
     * 被代理类
     */
    public class Admin implements Manager{
        @Override
        public void doSomething() {
            System.out.println("Admin--doSomething");
        }
    }
    
    /**
     * 代理类
     */
    public class AdminProxy1 implements Manager {
    
        private Admin admin;
    
        public AdminProxy1(Admin admin) {
            this.admin = admin;
        }
    
        @Override
        public void doSomething() {
            System.out.println("adminProxy1 -- doSomething");
            admin.doSomething();
        }
    }
    
    /**
     * 代理类
     */
    public class AdminProxy2 implements Manager {
    
        private Admin admin;
    
        public AdminProxy2(Admin admin) {
            this.admin = admin;
        }
    
        @Override
        public void doSomething() {
            System.out.println("adminProxy2 -- doSomething");
            admin.doSomething();
        }
    }
    
    /**
     * 使用类
     */
    public class Client {
    
        public static void main(String[] args) {
            Admin admin = new Admin();
    
            //代理1执行
            AdminProxy1 adminProxy1 = new AdminProxy1(admin);
            adminProxy1.doSomething();
    
            //代理2执行
            AdminProxy2 adminProxy2 = new AdminProxy2(admin);
            adminProxy2.doSomething();
        }
    }
    

    缺点:静态代理中,需要将被代理类中所有的方法实现一遍,并且为每个方法附加相似的代码逻辑;另外如果要添加的附加功能
    的类有多个,需要针对每个类创建一个代理类,增加维护成本。

    动态代理

    不用事先为每个原始类编写代理类,而是在运行的时候,动态的创建原始类对应的代理类,然后在系统中庸代理类替换原始类。
    Java 语言本身就已经提供了动态代理的语法。

    /**
     * 抽象接口
     */
    public interface Moveable {
    
        void move();
    }
    
    /**
     * 被代理类
     */
    public class Car implements Moveable {
        @Override
        public void move() {
            System.out.println("汽车行驶中...");
        }
    }
    
    /**
     * 事务处理器
     */
    public class TimeHandler implements InvocationHandler {
        private Object target;
    
        public TimeHandler(Object target) {
            this.target = target;
        }
    
    
        /**
         *
         * @param proxy 被代理的对象
         * @param method 被代理对象的方法
         * @param args 方法参数
         * @return  方法返回值
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
            method.invoke(target,args);
            long stopTime = System.currentTimeMillis();
            System.out.println("汽车结束行驶");
            System.out.println("汽车行驶时间:"+(stopTime - startTime)+"毫秒");
            return null;
        }
    }
    
    /**
     * 使用类
     */
    public class Client {
        public static void main(String[] args) {
            Car car = new Car();
    
            ClassLoader classLoader = car.getClass().getClassLoader();
            Class<?>[] clsArr = car.getClass().getInterfaces();
            InvocationHandler handler = new TimeHandler(car);
    
            Moveable moveable = (Moveable) Proxy.newProxyInstance(classLoader,
                                                        clsArr,
                                                        handler);
            moveable.move();
        }
    }
    
    

    cglib代理

    cglib代理使用需要引入额外的jar包 cglib.jar

    /**
     * 被代理类
     */
    public class Train {
        public void move(){
            System.out.println("火车行驶中...");
        }
    }
    
    /**
     * 代理类
     */
    public class CGLibProxy implements MethodInterceptor {
        private Enhancer enhancer = new Enhancer();
    
        public Object getProxy(Class<?> clazz){
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        /**
         * 拦截所有目标类方法的调用
         * @param obj 目标实例对象,被代理类
         * @param method 被代理类的反射对象
         * @param args 方法参数
         * @param methodProxy 代理类的实例
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("日志开始");
            methodProxy.invokeSuper(obj,args);
            System.out.println("日志结束");
            return null;
        }
    }
    
    
    /**
     * 使用类
     */
    public class Client {
        public static void main(String[] args) {
            CGLibProxy proxy = new CGLibProxy();
            Train train = (Train) proxy.getProxy(Train.class);
            train.move();
        }
    }
    
    

    代理模式的应用场景

    • 在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、日志等。我们将这些附加功能与业务功能解耦,放在代理类中统一处理,
    • 开发一个接口请求,一个支持缓存,一个支持实时查询。开发两个接口增加开发成本,应该是动态代理。如果是基于 Spring 框架来开发的话,那就可以在 AOP 切面中完成接口缓存的功能。在应用启动的时候,我们从配置文件中加载需要支持缓存的接口,以及相应的缓存策略(比如过期时间)等。当请求到来的时候,我们在 AOP 切面中拦截请求,如果请求中带有支持缓存的字段(比如http://…?..&cached=true),我们便从缓存(内存缓存或者 Redis 缓存等)中获取数据直接返回。

    附:
    静态代理需要代理类与被代理类同时实现接口
    动态代理类需要被代理类实现接口
    cglib不需要代理类或者被代理类实现接口

    相关文章

      网友评论

          本文标题:结构型-代理模式

          本文链接:https://www.haomeiwen.com/subject/edpevxtx.html