• java动态代理-面向对象的补充


    代理类是指在程序运行十创建的,可以根据调用处理器生成任何想要的结果。我们可以把面向对象理解为一个静态的过程,那么java动态代理就是面向对象的补充和完善。

    动态代理demo

    定义接口和实现类

    public interface ProductDao {
        void add();
    
        void update();
    
        void search();
    
        void delete();
    }
    
    public class ProductDaoImpl implements ProductDao {
        @Override
        public void add() {
            System.out.println("商品新增add");
        }
    
        @Override
        public void update() {
            System.out.println("商品修改update");
        }
    
        @Override
        public void search() {
            System.out.println("商品搜索search");
        }
    
        @Override
        public void delete() {
            System.out.println("商品删除delete");
        }
    }
    
    • 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

    实现代理工厂

    public class JdkProxyFactory implements InvocationHandler {
        public Object target;
    
        public JdkProxyFactory(Object target){
            this.target = target;
        }
    
        public Object createProxyInstance(){
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this
            );
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before(method);
            Object result = method.invoke(target, args);
            after(method);
            return result;
        }
    
        private void after(Method method) {
            // 目标方法执行后记录日志
            System.out.println("日志记录:" + method.getName() + "执行结束了...");
        }
    
        private void before(Method method) {
            // 目标方法执行前记录日志
            System.out.println("日志记录:" + method.getName() + "开始执行了...");
        }
    }
    
    • 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

    测试类

    public class JdkProxyFactoryTest {
        public static void main(String[] args) {
            ProductDaoImpl productDao = new ProductDaoImpl();
            ProductDao proxyInstance = (ProductDao) new JdkProxyFactory(productDao).createProxyInstance();
            //当执行这个方法时会执行代理方法,在方法前后增加日志
            proxyInstance.add();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    生成的代理类

    类信息动态生成的二进制字节码保存到硬盘中

    public class ProxyUtils {
        public static void generateClassFiles(Class clazz,String proxyName){
        	/*
        	* params: clazz 需要生成动态代理类的类
         	* proxyName: 为动态生成的代理类的名称
        	*/
            byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
            String path = clazz.getResource(".").getPath();
            System.out.println("path = " + path);
    
            FileOutputStream out = null;
            try{
                out = new FileOutputStream(path + proxyName + ".class");
                out.write(classFile);
                out.flush();
            }catch (Exception e){
    
            }finally {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 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

    测试类增加

    ProxyUtils.generateClassFiles(productDao.getClass(),"proxyProductDao");
    
    • 1

    生成的代理类

    在target包的相对路径下

    public final class proxyProductDao extends Proxy implements ProductDao {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m5;
        private static Method m6;
        private static Method m0;
        private static Method m4;
    
        public proxyProductDao(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void add() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void delete() throws  {
            try {
                super.h.invoke(this, m5, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void search() throws  {
            try {
                super.h.invoke(this, m6, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final void update() throws  {
            try {
                super.h.invoke(this, m4, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.my.dao.ProductDao").getMethod("add");
                m5 = Class.forName("com.my.dao.ProductDao").getMethod("delete");
                m6 = Class.forName("com.my.dao.ProductDao").getMethod("search");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
                m4 = Class.forName("com.my.dao.ProductDao").getMethod("update");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    
    • 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
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    通过这个代理类可以了解到以下几点

    • JDK动态代理的目标类必须实现某个接口,这是由他的实现机制决定的
    • 代理类的仅有一个构造函数,且唯一参数是InvocationHandler接口,这是给开发者自己实现的。
    • 代理类执行方法时,可以直观看到实际上是执行的是自己是实现的invoke方法

    源码解析

    动态代理的实现依赖两个关键类
    Proxy.newProxyInstance(ClassLoader classLoader,Interface[] interfaces,InvocationHandler h):构造实现指定接口的代理类的一个新实例,所有方法会调用给定处理器对象的 invoke 方法
    InvocationHandler:定义了代理对象调用方法时希望执行的动作,用于集中处理在动态代理类对象上的方法调用

    //简化代码
    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            final Class<?>[] intfs = interfaces.clone();
            Class<?> cl = getProxyClass0(loader, intfs);
            try {
            	//获取构造函数
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                //反射获取对象
                return cons.newInstance(new Object[]{h});
            } 
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    总结

    优点:

    • 动态代理减少了重复代码,提高了代码的可维护性和可读性。
    • 通过动态代理,可以在不修改原始代码的情况下添加新的功能,如日志记录、性能监控等。
      缺点:
    • 动态代理基于反射机制,可能会影响性能。
    • 无法代理final类或方法,也无法代理static方法。
  • 相关阅读:
    【Quark RISC-V】流水线CPU设计(4)数据冒险的处理(主要解决方案:流水线暂停、数据转发、乱序执行)
    Vue-声明周期函数
    linux ioctl 理解
    Find My运动相机|苹果Find My技术与相机结合,智能防丢,全球定位
    【C++】搜索二叉树/KVL树
    Linux C 多线程
    客路旅行(KLOOK)面试(部分)(未完全解析)
    leetcode-1. 两数之和
    java springboot VUE粮食经销系统开发mysql数据库web结构java编程计算机网页源码maven项目
    MCE | 衰老“走过”的信号途径
  • 原文地址:https://blog.csdn.net/qq_51059003/article/details/136512699