zoukankan      html  css  js  c++  java
  • Java基础加强——动态代理

    代理模式:

      为其他对象提供一种代理以控制对这个对象的访问。

      代理模式主要分为两类:

        静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
        动态代理:在程序运行时,运用反射机制动态创建而成

     1.静态代理相对好理解一些,来看下面的代码:

        接口 Count.java

    /**
     * 账户接口
     * @author jiangbei01
     *
     */
    public interface Count {
        void add();
        void update();
    }

        实现类 CountImpl

    package cn.test;
    
    public class CountImpl implements Count {
    
        @Override
        public void add() {
            System.out.println("真实对象.add");
        }
    
        @Override
        public void update() {
            System.out.println("真实对象.update");
        }
    
    }

        代理对象CountProxy.java

    package cn.test;
    
    public class CountProxy implements Count {
    
        //持有真实对象引用
        private CountImpl countImpl;
        //覆盖默认构造器
        public CountProxy(CountImpl countImpl) {
            super();
            this.countImpl = countImpl;
        }
    
        @Override
        public void add() {
            System.out.println("代理对象执行add前");
            countImpl.add();
            System.out.println("代理对象执行add后");
        }
    
        @Override
        public void update() {
            System.out.println("代理对象执行update前");
            countImpl.update();
            System.out.println("代理对象执行update后");
        }
    
    }

        看看测试代码:

    public class Test01 {
    
        public static void main(String[] args) {
            CountImpl countImpl = new CountImpl();
            CountProxy countProxy = new CountProxy(countImpl);
            countProxy.add();
            System.out.println("===========================");
            countProxy.update();
        }
    }

        运行结果也容易得出:

    代理对象执行add前
    真实对象.add
    代理对象执行add后
    ===========================
    代理对象执行update前
    真实对象.update
    代理对象执行update后

      容易看出静态代理缺点:每个代理只能为一个接口服务,并且重复代码量大!

    2.动态代理:java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

      每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,

      当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

      推荐博客:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

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

      在触发(invoke)真实角色的方法之前或者之后做一些额外的业务。那么,为了构造出具有通用性和简单性的代理类,

      可以将所有的触发真实角色动作交给一个触发的管理器,让这个管理器统一地管理触发。这种管理器就是Invocation Handler。

      推荐文档:http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml

      我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

      Proxy类提供的方法:

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

    其中最后一个参数 InvocationHandler h 得到InvocationHandler接口的子类实例 

      ClassLoader loader用来指明生成代理对象使用哪个类装载器,(Proxy.class.getClassLoader())

      Class<?>[] interfaces用来指明生成哪个对象的代理对象,通过接口指定,

      InvocationHandler h用来指明产生的这个代理对象要做什么事情。

      下面来看一个例子:

      先定义一个接口:Person.java

    public interface Person {
    
        String sing(String musicName);
        String speak(String text);
    }

      给出一个实现类:薛之谦 XueZhiQian.java

    public class XueZhiQian implements Person {
    
        @Override
        public String sing(String musicName) {
            System.out.println("薛之谦唱了 "+musicName);
            return "歌曲唱完,谢谢各位!";
        }
    
        @Override
        public String speak(String text) {
            System.out.println("薛之谦说了 "+text);
            return "话已讲完,谢谢各位!";
        }
    
    }

        生成代理对象的代理类:XueZhiQianProxy.java

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class XueZhiQianProxy {
    
        //要代理的对象
        private Person xzq = new XueZhiQian();
        
        public Person getProxy(){
            return (Person)Proxy.newProxyInstance(XueZhiQianProxy.class.getClassLoader(), 
                    xzq.getClass().getInterfaces(), 
                    new InvocationHandler() {
                        
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            if(method.getName().equals("sing")){
                                System.out.println("找薛之谦唱歌需要先交2W!");
                                return method.invoke(xzq, args);
                            }
                            if(method.getName().equals("speak")){
                                System.out.println("找薛之谦唱歌需要先交10W!");
                                return method.invoke(xzq, args);
                            }
                            return null;
                        }
                    });
        }
    }

        测试代码:

    public class Test01 {
    
        public static void main(String[] args) {
            XueZhiQianProxy proxy = new XueZhiQianProxy();
            Person p = proxy.getProxy();
            String s1 = p.sing("演员");
            System.out.println(s1);
            String s2 = p.speak("段子");
            System.out.println(s2);
        }
    }

        测试结果:

    找薛之谦唱歌需要先交2W!
    薛之谦唱了 演员
    歌曲唱完,谢谢各位!
    找薛之谦唱歌需要先交10W!
    薛之谦说了 段子
    话已讲完,谢谢各位!

      

  • 相关阅读:
    简单小巧的跨平台共享内存代码
    调试发行版程序 (二)
    休息日公园独步偶得
    Minimum Depth of Binary Tree
    LeetCode Length of Last word
    黑书 折纸痕 uva 177
    Palindrome Partitioning II leetcode
    Acumem ThreadSpotter
    C++ string int 转换 split
    Valid Palindrome Leetcode
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6828086.html
Copyright © 2011-2022 走看看