zoukankan      html  css  js  c++  java
  • 【设计模式】——代理模式

    代理模式:

        代理模式为其他的对象增加一个代理对象,进行访问控制。从而避免直接访问一个对象,造成效率或者安全性上的降低。去掉了某些功能,或提供了某些格外的服务。

    应用场景:

         1 远程代理,为一个远程对象,创建一个本地的代理对象。每次访问,直接访问本地代理对象即可。

      2 虚拟代理,如果对象很大,直接访问开销很大,可以为他创建一个代理对象,只生成关键的信息即可。

      3 保护代理,(权限控制)为某个对象增加一种保护机制,只有一定的权限才能通过这个代理,访问后面的对象。

      4 智能引用代理,提供目标对象一些额外的服务。

    一、静态代理

      被代理类和代理类通过继承相同的接口。

    1.创建Movable接口

    public interface Movable {
        public void move();
    }

    2.创建被代理类,实现了Movable接口

    public class Car implements Movable {
    
        @Override
        public void move() {
            try {            
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("汽车行驶中……");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

    3.创建一个时间的代理类,实现了Movable接口

    public class TimeProxy implements Movable{
        
        public TimeProxy(Movable m) {
            super();
            this.m = m;
        }
        private Movable m;
        @Override
        public void move() {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
            m.move();
            long endTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶,行驶时间为:"+(endTime-startTime)+"毫秒");
        }
        
    }

    4.如果存在多个代理类,如一个日志的代理类

    public class LoggerProxy implements Movable{
        
        public LoggerProxy(Movable m) {
            super();
            this.m = m;
        }
    
        private Movable m;
        
        @Override
        public void move() {
            System.out.println("开始记录日志");
            m.move();
            System.out.println("记录日志结束");
        }
    
    }

    5.客户端调用

    public class Client {
        public static void main(String[] args) {
            Car car = new Car();
            TimeProxy time = new TimeProxy(car);
            LoggerProxy log = new LoggerProxy(time);
            log.move();
        }
    }

    6.结果显示

                                      

    二、动态代理

    1、省略静态代理的1,2步骤。即已经有了movable接口和car类

    2、创建时间代理,并且继承了 InvocationHandler 接口,实现了invoke()方法。在invoke()方法的前后增加业务逻辑。

    public interface InvocationHandler{  
      Object invoke(Object proxy, Method method, Object[] args)  
             throws Throwable;  
    } 

     1. proxy就是通过 Proxy.newProxyInstance()方法创建的动态代理类,它实现了指定的interfaces接口。 通常这个对象在invoke函数中不使用。

       2. Method 表示动态代理类所实现的接口中的方法。通过 Method 对象可以获取方法名、参数类型、返回类型等信息。

       3. Object[] args 包含了传入动态代理类所实现的方法的参数值。

    public class TimeProxy implements InvocationHandler {
    
        public TimeProxy(Object target) {
            super();
            this.target = target;
        }
    
        Object target;
        
        /**参数:
         * proxy:被代理的对象
         * method:被代理的方法
         * arg:方法的参数
         * 返回object对象
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] arg)
                throws Throwable {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
            method.invoke(target);
            long endTime = System.currentTimeMillis();
            System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+"毫秒");
            return null;
        }

    3.客户调用,用到Proxy类中的newProxyInstance()方法,使用Proxy.newProxyInstance()方法创建动态代理类,方法定义:

    public static Object newProxyInstance(ClassLoader loader,  
                                          Class<?>[] interfaces,  
                                          InvocationHandler h)  
    1. ClassLoader :加载动态代理类的类加载器
    2. interfaces   :该动态代理类所要实现的接口
    3. InvocationHandler:事件处理,转发所有的方法调用代理。
    4. 函数返回创建的代理类,实现了interfaces接口
    public class Client {
        public static void main(String[] args) {
            Car car = new Car();
            Class<?>cls = car.getClass();
            TimeProxy handle = new TimeProxy(car);
            /*
             * 参数分别为
             */
            Movable m = (Movable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),handle);
            m.move();
        }
    }

    4.运行结果为

                                

    三、运用cglib生成代理

    1.引用cglib-nodep-2.1_3 jar包

    2.创建一个类,如Car

    public class Car {
        public void move(){
            System.out.println("汽车行驶中……");
        }
    }

    3.创建一个cglib代理。通过获得动态代理,拦截所有目标类方法的调用

    public class CglibProxy implements MethodInterceptor {
        
        private Enhancer enhancer = new Enhancer();
        
        //获得动态代理
        public Object getProxy(Class cls){
            enhancer.setSuperclass(cls);
            enhancer.setCallback(this);
            return enhancer.create();
        }
        
        //拦截所有目标类方法的调用
        @Override
        public Object intercept(Object obj, Method method, Object[] arg,
                MethodProxy proxy) throws Throwable {
            //添加业务逻辑
            System.out.println("开始记录日志");
            proxy.invokeSuper(obj, arg);
            System.out.println("记录日志结束");
            return null;
        }
    
    }

    4.Client客户端

    public class Client{
    
        public static void main(String[] args) {
            CglibProxy proxy = new CglibProxy();
            Car car = (Car) proxy.getProxy(Car.class);
            car.move();
        }
    
    }

    5.运行结果

                                         

    具体原理待完善……因为我还没有完全搞明白!

  • 相关阅读:
    Entity Framework 4 in Action读书笔记——第七章:持久化对象到数据库:使用SaveChanges持久化实体
    ASP.NET MVC+Colorbox做的一个Demo(一)
    Entity Framework 4 in Action读书笔记——第七章:持久化对象到数据库:持久化的一些技巧
    NHibernate初学者指南(4):定义数据库架构
    Entity Framework 4 in Action读书笔记——第六章:理解实体的生命周期(三)
    NHibernate初学者指南(1):开篇
    Entity Framework 4 in Action读书笔记——第七章:持久化对象到数据库:持久化修改的实体到数据库
    Java面试题每日五题(2010/02/26)
    Notes for Hadoop the definitive guide
    简明Java笔记
  • 原文地址:https://www.cnblogs.com/doudingbest/p/4963249.html
Copyright © 2011-2022 走看看