• 代理模式(Proxy)--动态代理(JDK)


    在是上一篇博客中实现了静态代理。

    在上篇的结尾提到了一个问题:

    思考:如果我们下需要对火车,自行车实现相同的代理,我们又该如何实现呢?

    这篇博客就来解决这个问题:

    解决这类问题需要用到动态代理技术,实现对不同的类,不同方法的代理

    1,动态代理的实现方式:

    动态代理其实就是在代理类和被代理类之间加入了InvocationHandler类(事物处理器),像我们的时间处理,日志处理都是在事物处理器中完成的。

    (1)InvocationHandler中只有一个方法:invoke方法,

    这个方法有三个参数:

    Object:被代理类

    Memthod:被代理的方法

    Object[]:方法的参数数组

    (2)Proxy:产生动态代理的类

    通过newProxyInstance()可以产生一个动态代理类

    (3)代码实现

    package com.songyan.jdkproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    import javax.interceptor.InvocationContext;
    
    /**
     * 时间处理器
     * @author sy
     *
     */
    public class TimeHandler implements InvocationHandler
    {
        //构造器,传递参数
        private Object target;
        
        public TimeHandler(Object target) {
            this.target=target;
            
        }
        
        /**
         * @param proxy:被代理的对象
         * @param method:被代理对象的方法
         * @param args:被代理对象的参数
         * 
         * @return Object:调用方法的返回值
         */
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("时间记录开始~~");
            
            //直接调用被代理对象的方法
            method.invoke(target);
            
        
            System.out.println("时间记录结束~~");
            return null;
        }
        
        
    
    
    }
    package com.songyan.jdkproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    import com.songyan.proxy.Car;
    import com.songyan.proxy.Moveable;
    
    public class DyTest {
    public static void main(String[] args) {
        Car car=new Car();
        //创建事务处理器
        InvocationHandler timeHandler= new TimeHandler(car);
        Class cla=car.getClass();
        /**
         * 第一个参数:loader类加载器
         * 第二个参数:interfaces实现接口
         * 第三个参数:h InvocationHandler
         */
        //动态创建代理类
        Moveable m=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), timeHandler);
        m.move();
    }
    }

     

    (4)总结一下

    动态代理首先是被代理对象首先要实现某些接口,在运行的时候产生了一个Class对象,就是我们的代理类

    然后声明一个Handler来接管我们实际的工作(比如说我们要实现的日志的功能是在handler里面实现的)

    (5)动态代理的实现步骤

      1)创建一个实现了InvocationHandler接口的类(事务处理器i),他必须实现invoke方法,在这个方法中实现逻辑代码

      2)创建被代理的类以及接口

      3)调用Proxy中的静态方法newProxyInstance创建一个代理类

      4)通过代理调用方法

    (6)作业:在上面的基础上试下功能的叠加(代理不仅能记录时间更能记录日志)

     在上面代码的基础上添加以下代码

     S1:记录日志的代理类

    package com.songyan.jdkproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 记录日志的代理类
     * @author sy
     *
     */
    public class LogHandler implements InvocationHandler {
        private Object obj;
        
        /**
         * 通过构造函数传值
         * @param obj
         */
        public LogHandler(Object obj)
        {
            this.obj=obj;    
        }
        
        /**
         *编写逻辑代码
         */
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("log start ~~~");
            method.invoke(obj);
            System.out.println("log end~~");
            return null;
        }
    
    }

     S2:测视类

    package com.songyan.jdkproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    import com.songyan.proxy.Car;
    import com.songyan.proxy.Moveable;
    
    public class DyTest {
    public static void main(String[] args) {
        Car car=new Car();
        //创建记录时间的事务处理器
        InvocationHandler timeHandler= new TimeHandler(car);
        Class cla=car.getClass();    
        //获得记录时间的代理
        Moveable timeProxy=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), timeHandler);
        //创建记录日志的事物处理器
        InvocationHandler logHandler= new LogHandler(timeProxy);
        //获得记录日志的代理
        Moveable logProxy=(Moveable) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), logHandler);
        //通过代理完成操作
        logProxy.move();
    }
    }

     缺点:被代理的对象必须实现接口才能产生代理对象,如果没有接口将不能使用动态代理技术(没有实现接口的对象可以使用CGLIB技术产生代理对象)

     动态代理的第二种实现实现方式:CGLIB

  • 相关阅读:
    css3中的位置移动
    css中伪元素选择器
    css中伪类选择器
    html5之属性选择器
    html5的文本属性
    html5的视频和音频使用
    常用的linux命令
    常见的http状态码
    springboot之安装和启动es
    linux版本的jdk安装
  • 原文地址:https://www.cnblogs.com/excellencesy/p/9124884.html
Copyright © 2020-2023  润新知