zoukankan      html  css  js  c++  java
  • java之动态代理

    Java之动态代理

    基本说明

    • 我们的目标是:在不改变目标对象方法的情况下对方法进行增强!

    • 动态代理类的字节码在程序运行时由Java反射机制动态生成,而无需手动编写它的源代码。

      • 简化了编程工作
      • 提高了软件系统的可扩展性
    • Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

    例子

    • 目标:现在有一个linux命令的接口LinuxService,接口中有个方法是创建目录的方法mkdir,想在创建目录的时候能指定一个目标路径。但是不改变LinuxService中的方法。
    • 方案:使用动态代理,在使用LinuxService接口中的mkdir时,代理对象指定目录,但在调用方看来,使用的就是LinuxService类的实例中的mkdir方法。

    代码

    接口LinuxService

    public interface LinuxService {
        /**
         * make directory, 创建目录
         */
        void mkdir();
        /**
         * 如果文件不存在,则会建立空文件;如果文件已经存在,则会修改文件的时间戳
         */
        void touch();
        /**
         * 编辑文件
         */
        void vim();
        /**
         * 连接文件并打印输出到标准输出  查看文件内容
         */
        void cat();
    }
    

    实现类LinuxServiceImpl

    public class LinuxServiceImpl implements LinuxService {
        private static String centreMessage = "我的核心实现是:";
        @Override
        public void mkdir() {
            System.out.println(centreMessage+"创建一个文件夹!");
        }
        @Override
        public void touch() {
            System.out.println(centreMessage+"创建一个用来编辑的文件!");
        }
        @Override
        public void vim() {
            System.out.println(centreMessage+"打开上面的文件并编辑!");
        }
        @Override
        public void cat() {
            System.out.println(centreMessage+"查看编辑过后的文件!");
        }
    }
    

    想要代理接口的代理对象

    public class LinuxServiceProxy implements InvocationHandler {
       /**
        * 要代理的核心对象  B是A的代理,则target=A
        * B = LinuxServiceProxy     A = LinuxService
        */
        private Object target;
        public LinuxServiceProxy(Object target){
            this.target = target;
        }
        /**
         * jdk动态代理
         * @param proxy  指被代理的对象。
         * @param method  要调用的方法
         * @param args  方法调用时所需要的参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("=======代理对象开始工作========");
            System.out.println("进入/Users/mac/Documents目录下后,创建一个新目录test,之后在/test中创建文件以及编辑文件!");
            //执行真正的核心的方法 即执行LinuxService中接口中真正关心的方法。
            Object result=method.invoke(target, args);
            System.out.println("=======执行结束后跟我说一下========");
            return result;
        }
    }
    

    执行类

    public class TestLinuxProxy {
        public static void main(String[] args) {
            /**
             * 有一个linux方法的接口,它定义了要实现这些方法的规范,LinuxServiceImpl是接口的具体实现。
             * 我要用它方法的具体实现,但我想先指定一个目录。
             */
            LinuxService linuxService = new LinuxServiceImpl();
            /**
             * 想指定一个目录,但是LinuxService并没有提供指定目录的功能
             * 我去找它的代理。
             */
            LinuxServiceProxy linuxServiceProxy = new LinuxServiceProxy(linuxService);
            /**
             * Proxy类是专门完成代理的操作类,通过newProxyInstance方法为接口动态的生成实现类。
             * 尽管我想指定一个目录, 但我核心是想调用LinuxService中的方法,因为我最终要调用的对象应该是	LinuxService下面的方法。
             * 底层的实现我不在乎,在乎的是我调用的是LinuxService接口中的方法
             */
            /**
             * 三个参数的说明:
             * ClassLoader loader:目标类加载器
             * Class<?>[] interfaces:目标类实现的接口
             * InvocationHandler h:得到InvocationHandler接口的子类实例  即目标类的代理对象
             */
            LinuxService asr = (LinuxService) Proxy
                    .newProxyInstance(linuxService.getClass().getClassLoader(),
                                      linuxService.getClass().getInterfaces(),
                                      linuxServiceProxy);
            /**
             * 调用生成目录的方法,用返回的代理。
             */
            asr.mkdir();
        }
    }
    

    结果

    =======代理对象开始工作========
    进入/Users/mac/Documents目录下后,创建一个新目录test,之后在/test中创建文件以及编辑文件!
    我的核心实现是:创建一个文件夹!
    =======执行结束后跟我说一下========
    

    原创不易,欢迎转载,转载时请注明出处,谢谢!
    作者:潇~萧下
    原文链接:https://www.cnblogs.com/manongxiao/p/11774550.html

  • 相关阅读:
    【Educational Codeforces Round 33 B】Beautiful Divisors
    【Educational Codeforces Round 33 A】Chess For Three
    【习题 6-7 UVA
    【习题 6-6 UVA
    【习题 6-5 UVA-1600】Patrol Robot
    【习题 6-4 UVA-439】Knight Moves
    【习题 6-3 UVA
    【POJ1144】Network(割点)(模板)
    【CF711D】Directed Roads(环,强连通分量)
    【CF711C】Coloring Trees(DP)
  • 原文地址:https://www.cnblogs.com/manongxiao/p/11774550.html
Copyright © 2011-2022 走看看