• 23种设计模式之jdk动态代理设计模式实战



    前言

    JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的;
    JDK中所要进行动态代理的类必须要实现一个接口
    需求:
    计算一个类中,每个被调用的方法运行时长

    二、具体代码

    1.定义接口IProduct

    package design.patterns.proxy;
    
    public interface IProduct {
        String sell(Float money);
        void afterSell();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.定义实现类Product

    package design.patterns.proxy;
    
    import java.util.concurrent.TimeUnit;
    
    public class Product implements IProduct {
        @Override
        public String sell(Float money) {
            System.out.println("代理员交给工厂:" + money);
            return "aaa";
        }
    
        @Override
        public void afterSell() {
            System.out.println("代理员做售后。。等待5秒");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (Exception ignore) {
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.定义抽象调用处理器

    package design.patterns.proxy;
    
    import java.lang.reflect.InvocationHandler;
    
    /**
     * 类名: MyHandler
     * 描述: 添加获取目标实例的方法
     * 日期: 2022/6/28-14:08
     */
    public abstract class MyHandler<T> implements InvocationHandler {
        protected T targetInstance;
    
        public MyHandler(T targetInstance) {
            this.targetInstance = targetInstance;
        }
    
        public T getTargetInstance() {
            return targetInstance;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.定义调用实际处理器实现类

    动态计算方法运行时长

    package design.patterns.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 类名: CalcTimeHandler
     * 描述: 动态计算方法运行时长
     * 日期: 2022/6/28-10:59
     */
    public class CalcTimeHandler<T> extends MyHandler<T> implements InvocationHandler {
    
        public CalcTimeHandler(T targetInstance) {
            super(targetInstance);
        }
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //这些方法不进行增强处理控制 //边界判断
            if ("equals getClass hashCode toString wait notifyAll".contains(method.getName())) {
                return method.invoke(targetInstance, args);
            }
            long startTime = System.currentTimeMillis();
            Object invoke = method.invoke(targetInstance, args);
            long end = System.currentTimeMillis();
            System.out.format("%s方法执行时间:%s毫秒%n", method.getName(), end - startTime);
            return invoke;
        }
    }
    
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31

    5.定义jdk动态代理工厂

    该静态工厂使用的是泛型类

    package design.patterns.proxy;
    
    import design.patterns.decorate.CalcTimeHandler;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    /**
     * 类名: MyJdkProxyFactory
     * 描述:
     * 日期: 2022/6/27-17:25
     *
     */
    public class MyJdkProxyFactory {
        /**
         * 泛型静态工厂方法:
         * 被代理的对象一定要实现一个接口
         * @param interfaces
         *              被代理对象实例.getClass().getInterfaces()
         * @param handler
         *             {@link InvocationHandler} 接口的实现类
         * @param <T>
         * @return
         */
        private static <T> T getProxy(Class<?>[] interfaces, InvocationHandler handler) {
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, handler);
        }
        /**
         *   对 {@link #getProxy(Class[], InvocationHandler)} 方法的简化
         *   增加了一层抽象父类,以方便获取目标实例的class对象 方便扩展
         *  泛型静态工厂方法:
         * 被代理的对象一定要实现一个接口
         * @param handler {@link MyHandler} 接口的实现类
         * @param <T>
         * @return
         */
        private static <T> T getProxy(MyHandler handler) {
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), handler.getTargetInstance().getClass().getInterfaces(), handler);
        }
    
        private static <T> T getProxy2(MyHandler handler) {
            return (T) Proxy.newProxyInstance(handler.getClass().getClassLoader(), handler.getTargetInstance().getClass().getInterfaces(), handler);
        }
    
    }
    
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    客户端调用

    
        public static void main(String[] args) {
            IProduct product = new Product();
            IProduct productProxy = MyJdkProxyFactory.getProxy(new CalcTimeHandler<>(product));
            //无感地对代码进行了动态的增强控制
            //调用代理实例的方法对原实例进行动态增强
            System.out.println(productProxy.sell(3f));
            productProxy.afterSell();
    
            System.out.println(productProxy.hashCode());
            System.out.println(product.hashCode());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述


    总结

    提示:这里对文章进行总结:

    在不改变原有代码的基础上对代理对象的方法进行了动态的增强
    核心代码逻辑:对代理对象的每个方法进行计算方法调用运行时长
    在这里插入图片描述

  • 相关阅读:
    jenkins持续集成、持续交付配置,以及对应Gitlab配置
    awk从入门到入土(16)awk变量类型探讨--关于数字和string两种类型
    qt信号与槽
    mysql redo 日志 、 undo 日志 、binlog
    处理机调度算法
    工作杂记-YUV的dump和read
    元宇宙侵权,虚拟世界还有法律吗?
    计组--输入输出系统--复习
    SMART PLC星三角延时启动功能块(梯形图FC)
    万字长文,手把手教你重构
  • 原文地址:https://blog.csdn.net/ljh_learn_from_base/article/details/125503683