• 设计模式之代理模式


    代理模式

    代理模式有动态代理和静态代理:静态代理模式中代理类是自己已经定理好的,在程序运行前就已经编译好了,然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。*相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法* 比如说,想要在每个代理的方法前都加上一个处理方法:

    JDK和CGLIB的区别

    JDK动态代理只能对实现了接口的类生成代理,而不能针对类,使用的是Java反射技术实现,不需要第三方库的支持,生成比较高效。

    CGLIB主要是针对一个类生成子类,覆盖其中的方法,是一种继承,并且需要第三方库asm字节码框架来支持。

    静态代理

    1.确定创建接口具体行为

    /**
     *  确定具体得行为接口
     * */
    public interface Person {
    
        // 上交班费
        void giveMoney();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.被代理对象 Student 实现接口,实现接口的具体行为的方法。

    /**
     * 被代理类
     */
    public class Student implements Person{
        @Override
        public void giveMoney() {
            System.out.println("学生上交班费....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.代理对象,因为代理对象需要去代理被代理对象,所以代理对象必须同样实现被代理对象类的接口。代理对象需要完成委托类预处理消息,消息过滤、转发,所以他必须得持有一个被代理对象,可以是继承或者是关联。

    /**
     * 学生的代理类  实现消息的委托、转发
     */
    public class StudentsProxy implements Person{
        // 消息的委托必须要交给被代理类,所以得关联一个被代理类
        private Student student;
    
        // 只会代理学生类
        public StudentsProxy(Person student){
            if (student.getClass() == Student.class){
                this.student = (Student) student;
            }
        }
    
        // 代替上交班费 调用被代理学生得上交班费行为
        @Override
        public void giveMoney() {
            // 代理类增加其他前置逻辑
            System.out.println("由我给你张三代缴班费吧。。。。。");
          student.giveMoney();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4.测试

    public class ProxyTest {
        public static void main(String[] args) {
            // 创建被代理类
            Student zhangSan = new Student();
            //  创建代理类并且代理张三上交班费
          Person studentsProxy  = new StudentsProxy(zhangSan);
          // 这样上缴班费就交给了学生得代理类了 用户无感知,只知道由谁能够给我实现上交班费功能即可。
          studentsProxy.giveMoney();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    动态代理

    1.确定创建接口得具体行为

    /**
     *  确定具体得行为接口
     * */
    public interface Person {
    
        // 上交班费
        void giveMoney();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.确定被代理对象实现接口,并且完成具体业务逻辑

    /**
     * 被代理类
     */
    public class Student implements Person {
        @Override
        public void giveMoney() {
            System.out.println("学生上交班费....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.自定义一个InvocationHandler类,并且实现InvocationHandler接口,这个类种会持有一个被代理对象target,并且InvocationHandler中有一个invoke方法,所有执行代理对象得方法都会被替换成执行invoke方法

    /**
     * @Author Tang
     **/
    public class StudentInvocationHandler<T> implements InvocationHandler {
    
        // 持有一个被代理对象
        T target;
    
        // 定义一个构造器
        public StudentInvocationHandler(T target) {
            this.target = target;
        }
    
        /**
         * proxy:代表动态代理对象
         * method 代表正在执行得方法
         * args:代表调用目标方法时传入的实参
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("执行方法....");
             method.invoke(target, args);
            System.out.println("执行结束,结果为:");
            return "执行成功....";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4.测试

    public class ProxyTest {
    
        public static void main(String[] args) {
    
            // 生成一个被代理类
            Person student =  new Student();
    
            StudentInvocationHandler<Person> studentInvocationHandler = new StudentInvocationHandler(student);
    
            // 使用Proxy得静态方法创建代理类   
          // 第一个参数是我们被代理的对象 也可以写成它实现的接口 
           // 第二个 interface对象数组 表明代理类实现了这些接口 那么代理类就可以调用接口中声明的所有方法。
          // 第三个 表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上
            Person personProxy=(Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, studentInvocationHandler);
            //使用动态代理类来
            personProxy.giveMoney();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    public static Object newProxyInstance(ClassLoader loader, 
                                                Class<?>[] interfaces, 
                                                InvocationHandler h)
    
    • 1
    • 2
    • 3

    这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:

    loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
    interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
    h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

  • 相关阅读:
    Vue2系列 -- 组件自动化全局注册(require.context)
    GBase 8c V3.0.0数据类型——HLL函数和操作符(哈希函数)
    C# 第五章『面向对象』◆第4节:析构函数destructor
    Oracle中LEFT JOIN后AND与WHERE的异同
    Android使用glide时报错“ ����: �޷�����Fragment Glide.with(getContext()) ^ �Ҳ���and”
    Servlet到底是什么(非常透彻)
    Flink-看完就会flink基础API
    Linux命令系列之ls——原来最简单的ls这么复杂
    『力扣刷题本』:轮转数组
    求所有质因子(Java)
  • 原文地址:https://blog.csdn.net/qq_50629351/article/details/127889928