zoukankan      html  css  js  c++  java
  • 代理模式

    静态代理

    1)定义一个接口

    package com.imooc.proxy;
    
    public interface Moveable {
        void move();
    }

    2)被代理类

    package com.imooc.proxy;
    
    import java.util.Random;
    
    public class Car implements Moveable {
    
        @Override
        public void move() {
            //实现开车
            try {
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("汽车行驶中....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    3)代理类

    日志代理:

    package com.imooc.proxy;
    
    public class CarLogProxy implements Moveable {
    
        public CarLogProxy(Moveable m) {
            super();
            this.m = m;
        }
    
        private Moveable m;
        
        @Override
        public void move() {
            System.out.println("日志开始....");
            m.move();
            System.out.println("日志结束....");
        }
    
    }

    记时代理

    package com.imooc.proxy;
    
    public class CarTimeProxy implements Moveable {
    
        public CarTimeProxy(Moveable m) {
            super();
            this.m = m;
        }
    
        private Moveable m;
        
        @Override
        public void move() {
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶....");
            m.move();
            long endtime = System.currentTimeMillis();
            System.out.println("汽车结束行驶....  汽车行驶时间:" 
                    + (endtime - starttime) + "毫秒!");
        }
    
    }

    测试类:

    package com.imooc.proxy;
    
    public class Client {
    
        /**
         * 测试类
         */
        public static void main(String[] args) {
            Car car = new Car();
            CarLogProxy clp = new CarLogProxy(car);
            CarTimeProxy ctp = new CarTimeProxy(clp);
            ctp.move();
        }
    
    }

    结果:

    **聚合方式要优于继承方式

    继承:继承父类想要的功能

    聚合:传入参数,实现想要的父类

    如果为继承方式,如果日志和时间的位置要调换,那么需要新定义一个子类

    而继承方式只需要在测试类中,调换位置就行

    动态代理:

    动态代理不必为特定的对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理折Handler服务于各个对象

    接口被代理类不用改变

    时间代理类:!!继承InvocationHandler的接口

    package com.imooc.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class TimeProxyHandler implements InvocationHandler {
    
        private Object target;
        public TimeProxyHandler(Object target) {
            super();//调用父类的构造方法
            this.target = target;
        }
        
        /*
         * 参数:
         * proxy  被代理对象
         * method  被代理对象的方法
         * args 方法的参数
         * 
         * 返回值:
         * Object  方法的返回值
         * */
        @Override
        public Object invoke(Object proxy, Method mothod, Object[] args) throws Throwable {
            System.out.println("运行开始");
            long starttime = System.currentTimeMillis();
            mothod.invoke(target);
            long endtime = System.currentTimeMillis();
            System.out.println("运行结束,运行时间为:"+(endtime-starttime)+"毫秒");
            return null;
        }
        
        //获得代理对象
        public static Object getTimeProxy(Object object){
            InvocationHandler h = new TimeProxyHandler(object);
            Class<?> cls = object.getClass();
            /**
             * loader  类加载器
             * interfaces  实现接口
             * h InvocationHandler
             **/
            return Proxy.newProxyInstance(cls.getClassLoader(),
                                                    cls.getInterfaces(), h);
            
        }
    }

    测试类

    package com.imooc.proxy;
    
    public class Test {
            /**
             * JDK动态代理测试类
             */
            public static void main(String[] args) {
                Moveable m = (Moveable) TimeProxyHandler.getTimeProxy(new Car());
    /
    /返回代理类,代理类是JVM在内存中动态创建的,该类实现传入的接口数组的全部接口(的全部方法).
           m.move(); 
    }
    }

    InvocationHandler角色:

    代理模式:

    代理类处理的逻辑很简单:在调用某个方法前及方法后做一些额外的业务。

    动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。如下图所示:

     

    在这种模式之中:代理Proxy 和RealSubject 应该实现相同的功能,这一点相当重要。(我这里说的功能,可以理解为某个类的public方法)

    在面向对象的编程之中,如果我们想要约定Proxy 和RealSubject可以实现相同的功能,有两种方式:

        a.一个比较直观的方式,就是定义一个功能接口,然后让Proxy 和RealSubject来实现这个接口。(JDK机制)

        1.   获取 RealSubject上的所有接口列表;
        2.   确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;

        3.   根据需要实现的接口信息,在代码中动态创建 该Proxy类的字节码;

        4 .  将对应的字节码转换为对应的class 对象;

        5.   创建InvocationHandler 实例handler,用来处理Proxy所有方法调用;

        6.   Proxy 的class对象 以创建的handler对象为参数,实例化一个proxy对象

        b.还有比较隐晦的方式,就是通过继承。因为如果Proxy 继承自RealSubject,这样Proxy则拥有了RealSubject的功能,Proxy还可以通过重写RealSubject中的方法,来实现多态。(cglib机制)

    1.   查找A上的所有非final 的public类型的方法定义;

    2.   将这些方法的定义转换成字节码;

    3.   将组成的字节码转换成相应的代理的class对象;

    4.   实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)

    CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

    两者区别:

    java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

     

  • 相关阅读:
    js实现倒计时
    CSS解决ul下面最后一个li的margin
    js手动定时清除localStorage
    js应用中的小细节-时间戳的转换和input输入框有效数字
    javaScript将string转换成array,并将汉字按汉语拼音排序方法
    CSS3属性之text-overflow:ellipsis,指定多行文本中任意一行显示...
    移动端下拉刷新,向后台请求数据
    进程 线程 协程
    网络编程
    flask 2 进阶
  • 原文地址:https://www.cnblogs.com/L-a-u-r-a/p/8529245.html
Copyright © 2011-2022 走看看