为了账号安全,请及时绑定邮箱和手机立即绑定

模式的秘密---代理模式

难度中级
时长 2小时 0分
学习人数
综合评分9.70
184人评价 查看评价
9.8 内容实用
9.6 简洁易懂
9.7 逻辑清晰
  • 动态代理实现思路
    实现功能;通过Proxy的newProxyInstance返回代理对象
    1.声明一段源码(动态产生代理)
    2.编译源码(JDK Compiler API),产生新的类(代理类)
    3.将这个类load到内存当中,产生一个新的对象(代理对象)
    4.return 代理对象

    查看全部
  • 设计模式——代理模式(具备面向对象的设计思维、了解多态、反射机制)

    一、基本概念及分类

        1、定义:为其他对象提供一种代理以控制对这个对象的访问(购买火车票去代售网点、找代理),代理对象起到中介作用,可去掉功能服务或增加额外服务。

        2、常见的代理模式

            (1)远程代理:为不同地理的对象提供局域网代表对象(客户端、服务器等)

                     例如:连锁店查看门店经营情况(通过远程代理可以监控各个店铺,使之能直观地了解店内信息)

            (2)虚拟代理:格局需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建

                     例如:浏览网页中的图片时以默认图片显示,当图片加载完成后再查看

            (3)智能引用代理:提供给目标对象一些额外的服务

                     例如:火车票代售处、日志处理、权限管理、事务处理...

            (4)保护代理:控制对一个对象的访问权限

                     例如:浏览网页时,普通用户只有浏览权限,当用户注册登录后,才可以进行发帖、删除、评论等操作

    二、开发中的应用场景

    三、实现方式(以智能引用代理为例)

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

            实现例子:车辆在公路上行驶,通过代理实现车辆行驶的方法,增加一个记录车辆行驶的方法

       不使用代理正常实现:

    public interface Moveable{
        void move();
    }
    public class Car implements Moveable{
        
        @Override
        public void move(){
            long starttime = System.currentTimeMillis();
               System.out.println("汽车开始行驶...");
               //实现开车
               try{
                   Thread.sleep(new Random().nextInt(1000));
                   System.out.println("汽车行驶中...");
               }catch(InterruptedException e){
                   e.printStackTrace();
               }
               long endtime = System.currentTimeMillis();
               System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
        }
    }
    public class Client{
        public static void main(String[] args){
            Car car = new Car();
            car.move();
        }
    }

        (1)通过继承的方式实现:

    public interface Moveable{
       void move();
    }
    public class Car implements Moveable{
       
       @Override
       public void move(){
               //实现开车
               try{
                   Thread.sleep(new Random().nextInt(1000));
                   System.out.println("汽车行驶中...");
               }catch(InterruptedException e){
                   e.printStackTrace();
               }
       }
    }
    public calss Car2 extends Car{
        @Override
           public void move(){
               long starttime = System.currentTimeMillis();
               System.out.println("汽车开始行驶...");
               super.move();
               long endtime = System.currentTimeMillis();
               System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
           }
    }
    public class Client{
       public static void main(String[] args){
           Moveable m = new Car2();
           m.move();
       }
    }

        (2)通过聚合(一个类当中调用另一个对象)的方式实现:

    public interface Moveable{
       void move();
    }
    public class Car implements Moveable{
       @Override
       public void move(){
               //实现开车
               try{
                   Thread.sleep(new Random().nextInt(1000));
                   System.out.println("汽车行驶中...");
               }catch(InterruptedException e){
                   e.printStackTrace();
               }
       }
    }
    public calss 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.move();
               long endtime = System.currentTimeMillis();
               System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
           }
    }
    public class Client{
       public static void main(String[] args){
           Car car = new Car();
           Moveable m = new Car3(car);
           m.move();
       }
    }

        

    思考:通过继承和聚合两种方式都能实现静态代理,但究竟哪种方式更好呢?

            以上是在实现对象方法move()的外层添加方法运行时间处理功能,想要增加权限管理、增加日志处理实现功能的叠加,通过两种方式示例:

        (1)通过继承方式实现(代理类会无限膨胀下去)

                先记录日志,再记录时间:需要先创建类Car4继承Car2或者Car,在move()方法前后先记录日志,再记录时间;

                先记录时间,再记录日志:需要先创建类Car5继承Car2或者Car,在move()方法前后先记录时间,再记录日志;

                先处理权限,再记录日志,再记录时间:需要先创建类Car6继承Car2或者Car,先处理权限,再记录日志,再记录时间;

                先处理权限,再记录时间,再记录日志:需要先创建类Car7继承Car2或者Car,先处理权限,再记录时间,再记录日志;

         (2)通过聚合方式实现 (代理类实现相同的接口,且代理之间相互传递、组合)

    public interface Moveable{
       void move();
    }
    public class Car implements Moveable{
       @Override
       public void move(){
               //实现开车
               try{
                   Thread.sleep(new Random().nextInt(1000));
                   System.out.println("汽车行驶中...");
               }catch(InterruptedException e){
                   e.printStackTrace();
               }
       }
    }
    public calss CarTimeProxy implements Moveable{
       private Moveable m;
       
       public CarTimeProxy (Moveable m){
           super();
           this.m = m;
       }
       @Override
           public void move(){
               long starttime = System.currentTimeMillis();
               System.out.println("汽车开始行驶...");
               m.move();
               long endtime = System.currentTimeMillis();
               System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
           }
    }
    public calss CarLogProxy implements Moveable{   
        private Moveable m;      
        public CarLogProxy (Moveable m){       
            super();       
            this.m = m;   
        }   
        @Override       
        public void move(){           
            System.out.println("日志开始...");          
            m.move();           
            System.out.println("日志结束...");       
        }
     }
     public class Client{   
         public static void main(String[] args){       
             Car car = new Car();       
             //先记录日志,再记录时间       
             CarTimeProxy ctp = new CarTimeProxy (car);        
             CarLogProxy  clp = new CarLogProxy (ctp);              
             clp.move();            
             //先记录时间,再记录日志        
             CarLogProxy  clp = new CarLogProxy (car);           
             CarTimeProxy ctp = new CarTimeProxy (car);        
             ctp .move(); 
         }  
     }

        思考:不同的类(Car,Train)实现相同的代理(TimeProxy,LogProxy)怎样实现(如果用静态代理的聚合方式实现,每增加一个类就要新创建新类的TimeProxy,LogProxy代理类,造成类膨胀)?

        有没有一种方法:能够动态产生代理,实现对不同类、不同方法的代理——动态代理

        2、动态代理(在代理类与被代理类之间加入了实现InvocationHandler【事务处理器】类)

            (一)JDK动态代理

                Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

                (1)Interface Invocationhandler:该接口中仅定义了一个方法

                         public Object invoke(Object obj,Method method, Object[] args)

                         在实际使用中,参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

                (2)Proxy:该类即为动态代理类

                         static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)

            JDK动态代理代码实现:

    public interface Moveable{
      void move();
    }
    public class Car implements Moveable{
      @Override
      public void move(){
              //实现开车
              try{
                  Thread.sleep(new Random().nextInt(1000));
                  System.out.println("汽车行驶中...");
              }catch(InterruptedException e){
                  e.printStackTrace();
              }
      }
    }
    public class TimeHandler implements InvocationHandler{
       private Object target;
       public TimeHandler(Object target){
           super();
           this.target = target;
       }
       /*
       *参数:
       *proxy:被代理的对象
       *method:被代理对象的方法
       *args:方法的参数
       *返回值:
       *Object:方法的返回值
       */
       @Override
       public Object invoke(Object proxy,Method method,Object[] args) throw Throwable{
           long starttime = System.currentTimeMillis();
           System.out.println("汽车开始行驶...");
           method.invoke(target);
           long endtime = System.currentTimeMillis();
           System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
       }
    }
    //JDK动态代理测试
    public class Test{
       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();
       }
    }

            所谓动态代理是在运行时生成的class,该class需要实现一组interface,使用动态代理类时,必须事先InvocationHandler接口。

            JDK动态代理实现步骤:

            1、创建一个实现皆苦InvocationHandler的类,它必须事先invoke()方法;

            2、创建被代理的类及接口;

            3、调用Proxy类的静态方法,创建一个代理类;

                 static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)

            4、通过代理调用方法。

            实现作业:实现Car类的多个动态代理类(记录日志、时间)

    实现作业:实现Car类的多个动态代理类(记录日志、时间)

            (二)CGLIB动态代理

            JDK动态代理与CGLIB动态代理的区别:

            JDK动态代理:

                1、只能代理实现了接口的类;

                2、没有实现接口的类不能实现JDK的动态代理。

            CGLIB动态代理:

                1、针对类来实现代理的;

                2、对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

        CGLIB动态代理实现代码示例(导包:cglib-nodep-2.2.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) throw Throwable{
           System.out.println("日志开始...");
           //代理类调用父类的方法
           proxy.invoke(obj,args);
           System.out.println("日志结束...");
           return null;
       }
    }
    public class Test{
       public static void main(String[] args){
           CglibProxy proxy = new CglibProxy();
           Train t = proxy.getProxy(Train.class);
           t.move();
      }
    }

    四、理解JDK动态代理的实现

     动态代理实现思路(实现功能:通过Proxy的newProxyInstance返回代理对象)

        1、声明一段源码(动态产生代理)

        2、编译源码(JDKCompiler API),产生新的类(代理类)

        3、将这个类load到内存当中,产生一个新的对象(代理对象)

        4、return代理对象

    代码实现:

    public class Proxy{
       public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
         String rt = "\r\t";
         String methodStr = "";
         for(Method m : infce.getMethods()){
            methodStr +="@Override" + rt +
           "public void "+m.getName()+"(){" + rt +
               /*
               "long starttime = System.currentTimeMillis();" + rt +
               "System.out.println("汽车开始行驶...");" + rt +
               "m."+m.getName()+"();" + rt +
               "long endtime = System.currentTimeMillis();" + rt +
               "System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");" + rt +
               */
               "try{" + rt +
                   "Method md =" + infce.getName() +".class.getMethod(\""+m.getName()+"\");" + rt +
                   "h.invoke(this,md);" + rt +
               "}catch(Exceotipn e){" + rt +
                   "e.printStackTrace();" + rt +
               "}" + rt +
           "}";
       }
       String str =
       "public calss $Proxy0 implements" + infce.getName()+ "{" + rt +
            
            "public $Proxy0 (InvocationHandler h){" + rt +
             "super();" + rt +
             "this.h = h;" + rt +
            "}" + rt +
            " private InvocationHandler h;" + rt +
            methodStr  + rt +
           "}";
           //String filename = System.getProperty("user.dir");
           //System.out.println(filename);//C:/Proxy        
           //产生代理类的Java文件        
           String filename = System.getProperty("user.dir")+"/bin/com/imooc/proxy/$Proxy0.java";
           File file = new File(filename);        
           //FileUtils(commons-io的jar包下的类)        
           FileUtils.writeStringToFile(file,str);        
           //编译        
           //拿到编译器        
           JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();        
           //文件管理者        
           StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null); 
           //获取文件        
           Iterable units = fileMgr.getJavaFileObjects(filename);        
           //编译任务        
           CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units);        
           //进行编译        
           t.call();        
           fileMgr.close();        
           //load到内存        
           ClassLoader cl = ClassLoader.getSystemClassLoader();       
            Class c = cl.loadClass("$Proxy0");        
            Constructor ctr = c.getConstructor(InvocationHandler.class);        
            System.out.println(c.getName());//$Proxy0        
            return ctr.newInstance(h);  
        }
    }
    /*测试类*/
    public class Client{    
       public static void main(String[] args) throws Exception{
           Car car = new Car();
           InvocationHandler h = new TimeHandler(car);
           Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);        
           m.move();
       }
    }
    public class Test{
       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);       
           System.out.println("代理类名字" + m.getClass().getName());//代理类名字$Proxy0       
           m.move();   
       }
    }
    public class InvocationHandler{
       public void invoke(Object o,Method m);
    }
    public class TimeHandler implements InvocationHandler{
       private O bject target;
       public TimeHandler(Object target){
           this.target = target;
       }
       @Override
       public void invoke(Object o,Method m){
           try{
               long starttime = System.currentTimeMillis();
               System.out.println("汽车开始行驶...");
               m.invoke(target);
               long endtime = System.currentTimeMillis();
               System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");
           }catch(Exception e){
               e.printStackTrace();
           }
       }
    }

    五、总结

    查看全部
  • 2222222222222222222222222222

    查看全部
  • 11111111111111111111111111111111

    查看全部
  • 22222222222222222222222222222222

    查看全部
  • 555555555555555555555555555

    查看全部
  • 333333333333333333333333333333333

    查看全部
  • 3333333333333333333333333333333333

    查看全部
  • 222222222222222222222222222222222222222

    查看全部
  • 实现静态代理的两种方式

    查看全部
  • 静态代理的概念

    查看全部
  • 智能引用代理的两种实现方式

    查看全部
  • 常见代理模式

    查看全部
  • 智能引用代理

    查看全部
  • 保护代理应用

    查看全部
  • 虚拟代理例子

    查看全部
  • 虚拟代理概念

    查看全部
  • 例 子 例 子

    查看全部
  • 远 程 代 理

    查看全部
  • 常用代理模式

    查看全部
  • 代理模式基本概念

    查看全部
  • 代理模式定义

    查看全部
首页上一页1234567下一页尾页

举报

0/150
提交
取消
课程须知
本课程是 Java 开发课程的高级课程,希望各位小伙伴们在学习本课程之前,了解以下内容: 1)初步具备面向对象的设计思维 2)了解多态概念 3)了解反射
老师告诉你能学到什么?
1、代理模式概念机分类 2、代理模式应用场景 3、掌握静态代理、动态代理运用 4、理解JDK动态代理实现原理

微信扫码,参与3人拼团

意见反馈 帮助中心 APP下载
官方微信
友情提示:

您好,此课程属于迁移课程,您已购买该课程,无需重复购买,感谢您对慕课网的支持!