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

    java代理模式是一种常见的设计模式。

    一、概念:为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。

    二、常见的代理模式有哪些?

    1. 远程代理:为不同地理的对象,提供局域网代表对象。
    2. 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。
    3. 保护代理:控制对一个对象访问的权限。
    4. 智能引用代理:提供对目标对象额外的服务。

    三、代理模式的两种实现方式

    1. 静态代理:代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。
    2. 动态代理

    四、示例

    1.通过继承实现静态代理

    首先,先写一个接口

    public interface Moveable {
        
        void move();
        
    }

    然后写接口的实现类

    public class Car implements Moveable {
    
        @Override
        public void move() {    
            //实现开车
            try {
                Thread.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

    接着是继承类,在继承类中,我们实现了父类中的方法,并增加了一些额外的功能,从而实现静态代理

    public class Car2 extends Car{
        
        @Override
        public void move(){
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶.......");
         //调用父类中的方法,实现该方法
    super.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }

    测试方法

    public class Test{
        public static void main(String[] args) {
            //使用继承方式实现
            Moveable m = new Car2();
            m.move();
        }
    }

    2.通过聚合实现静态代理

    编写聚合类(通过将参数传递进来,然后我们使用传递进来的参数,调用其方法,实现静态代理)

    public class Car3 implements Moveable{
    
        private Car car;    
        public Car3(Car car) {
            super();
            this.car = car;
        }
    
        @Override
        public void move() {
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶.......");
         //通过构造方法将car传进来,然后通过car调用方法 car.move();
    long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }

    测试方法

    public class Test {
        public static void main(String[] args) {
            //使用聚合方式实现
            Car car = new Car();
            Moveable m = new Car3(car);
            m.move();
            }
    }    

    使用继承实现静态代理,会让我们的代理类无限制的膨胀下去,所以推荐使用聚合实现静态代理。

    五、JDK动态代理

    1.定义

    在代理类和被代理类之间加上一个事务处理器,将我们需要处理的具体功能放在其中进行处理。

    InvocationHandler接口(事务处理器)中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args),在实际使用中,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。

    Proxy:该类即为动态代理类,通过newProxyInstance方法可以返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)。

    2.实现步骤

    1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,在invoke方法中添加具体的业务逻辑。
    2. 创建被代理的类和接口。
    3. 调用Proxy的静态方法newProxyInstance,动态创建一个代理类。
    4. 通过代理调用方法。

    3.示例

    public class TimeHandler implements InvocationHandler{    
        private Object target;
        public TimeHandler(Object target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶.......");
            method.invoke(target);
            long endtime = System.currentTimeMillis();
            System.out.println("汽车结束行驶......");
            System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!");        
            return null;
        }
    }
    public class TestProxy {
        public static void main(String[] args) {
            Car car  = new Car();
            InvocationHandler h = new TimeHandler(car);
            Class<?> cls = car.getClass();
            /**
             * loader 类加载器
             * interfaces 实现接口
             * h InvocationHandler 
             * */
            Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),
                    cls.getInterfaces(), h);
            m.move();
        }
    }

    六、CGLIB动态代理

     示例:

    首先需引入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();
        }
        /**
         * 拦截所有目标类方法的调用
         * obj 目标类的实例
         * m 目标方法的反射对象
         * args 方法的参数
         * proxy 代理类的实例
         * */
        @Override
        public Object intercept(Object obj, Method m, Object[] args,
                MethodProxy proxy) throws Throwable {
            System.out.println("日志开始......");
            //代理类调用父类的方法
            proxy.invokeSuper(obj, args);
            System.out.println("日志结束......");
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) {
            //创建返回代理类对象
            CglibProxy proxy = new CglibProxy();
            //为trian返回代理类对象
            Train t = (Train) proxy.getProxy(Train.class);
            //调用方法
            t.move();
        }
    }

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

    JDK动态代理:

    1. 只能代理实现了接口的类。
    2. 没有实现接口的类不能实现JDK的动态代理。

    CGLIB动态代理:

    1. 针对类来实现代理。
    2. 对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

    动态代理的典型应用:spring AOP:同时用到了JDK动态代理和CGLIB动态代理。

  • 相关阅读:
    如何使用jackson美化输出json/xml
    使用Jackson在Java中处理JSON
    用 Jackson 来处理 JSON
    writeValueAsString封装成工具类
    周鸿袆:360回归是出于国家安全考虑(硬件有硬件独特的规律,硬件不可能有很高的利润,核心的价值还是硬件背后承载的软件和云端的服务)
    Unicode 7.0.1中文支持非常好
    六个编程范型将改变你对编程的看法(好多奇怪的语言和奇怪的想法)
    delphi多版本安装方法
    UAC就不能一次添加、永久信任吗?
    数学符号及读法大全
  • 原文地址:https://www.cnblogs.com/libinhyq/p/9578902.html
Copyright © 2011-2022 走看看