美文网首页
01-设计模式:JDK动态代理

01-设计模式:JDK动态代理

作者: XAbo | 来源:发表于2021-01-06 22:13 被阅读0次

    代理模式:在不改变原有类的前提下,对原有类进行业务增强。
    动态与静态代理区别:动态代理的代理类是被用的时候在内存中创建。
    jdk方式代理类:必须实现的有接口。

    问题:如何给Manager方法add()执行前后增加额外的日志逻辑呢?


    package realclass;
    import interfaces.ControlDB;
    import interfaces.ControlUI;
    
    public class Manager implements ControlDB{
       
        @Override
        public void add() {
            // TODO Auto-generated method stub
           System.out.println("我是Manager,数据添加中……");
        }
    }
    

    1、静态代理

    package proxyclass;
    import realclass.Manager;
    import interfaces.ControlDB;
    import interfaces.ControlUI;
    
    public class ManagerLog_JT implements ControlDB  {
    
        private Manager manager ;
        public ManagerLog_JT(){
            manager=new Manager();
        }    
           @Override
        public void add() {
            // TODO Auto-generated method stub
            System.out.println("我是ManagerLog_JT,日志记录开始……");
            manager.add();
            System.out.println("我是ManagerLog_JT,日志记录结束……");
        }
    }
    

    2、聚合方式

    package proxyclass;
    import interfaces.ControlDB;
    
    public class ManagerLog_JH implements ControlDB {
    
       ControlDB controlDB;
       public ManagerLog_JH(ControlDB controlDB){
           this.controlDB=controlDB;
       }
       @Override
       public void add() {
           // TODO Auto-generated method stub
           System.out.println("我是ManagerLog_JH,日志记录开始……");
           controlDB.add();
           System.out.println("我是ManagerLog_JH,日志记录结束……");
       }
    }
    

    3、测试类:

    import interfaces.ControlDB;
    import proxyclass.ManagerLog_JH;
    import proxyclass.ManagerLog_JT;
    import realclass.Manager;
    
    public class ProxyTest {
        public static void main(String[] args) {
         // 正常调用Manager
          Manager manager= new Manager();
          manager.add();
          System.out.println("==============================分割线============================");
          System.out.println("为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:");
          System.out.println("————————————————————静态方式开始————————————————————");
          ControlDB  managerlog_jt=new ManagerLog_JT();
          managerlog_jt.add();
          System.out.println("————————————————————静态方式结束————————————————————");
          System.out.println("————————————————————聚合方式开始————————————————————");
          ControlDB managerlog_jh=new ManagerLog_JH(new Manager());
          managerlog_jh.add();
          System.out.println("————————————————————聚合方式结束————————————————————"); 
                
        }
    
    }
    

    4、结果

    我是Manager,数据添加中……
    ==============================分割线============================
    为Mnager的add方法执行前后添加日志记录的操作,使用静态代理和聚合方式实现:
    ————————————————————静态方式开始————————————————————
    我是ManagerLog_JT,日志记录开始……
    我是Manager,数据添加中……
    我是ManagerLog_JT,日志记录结束……
    ————————————————————静态方式结束————————————————————
    ————————————————————聚合方式开始————————————————————
    我是ManagerLog_JH,日志记录开始……
    我是Manager,数据添加中……
    我是ManagerLog_JH,日志记录结束……
    ————————————————————聚合方式结束————————————————————
    

    5、分析
    不管哪种方式最终结果是代码的臃肿:

    image.png

    6、动态代理

    原理:
    1.在运行时根据反射生成一个被代理对象类似的“内存对象”。
    2.“内存对象”可以执行原有对象的原生方法。
    3.在执行原生方法前后可以增加业务逻辑。
    4.增加的业务逻辑需用户自定义。

    jdk实现的动态代理应用

    package test;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import proxyclass.ManagerLog_Proxy;
    import realclass.Manager;
    
    public class ManagerInvocationHandler implements InvocationHandler {
            private Object obj; 
            public ManagerInvocationHandler(Object obj) {
                this.obj = obj;
            }
            
            public static  Object getProxyInstanceFactory(Object realObj){
            Class<?> classType = realObj.getClass(); 
           /* 参数1:被代理对象的类加载器,用来加载代理对象的字节码文件。
              参数2:被代理对象实现的接口,用来是代理对象与被代理对象保持方法一致。
              使用参数1、2保证了【原理1】
           */
            return Proxy.newProxyInstance(classType.getClassLoader(),classType.getInterfaces(), new ManagerInvocationHandler(realObj));
            }
        
        @Override
          //实现了【原理2 3 4】关键是该方法能被内存中的代理类调到
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {          
            System.out.println("before========日志生成");
            method.invoke(obj, args);       
            System.out.println("after=========日志结束");
            return null;
        }
    
    }
    

    动态代理的测试类:

    package test;
    import interfaces.ControlDB;
    import interfaces.ControlUI;
    import realclass.Manager;
    import realclass.UserA;
    
    public class ProxyTest {
        public static void main(String[] args) {
     
         System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
          //返回内存中的代理类(无逻辑的方法体)      
          Manager manager= new Manager(); 
          //拿到代理类,执行内存类中的方法
          ControlUI managerui= (ControlUI) ManagerInvocationHandler.getProxyInstanceFactory(manager);      
          managerui.change();    
       }
    }
    

    内存中的类$Proxy0:如何生成看后续JAVA反射专题,会模拟jdk生成动态类。

    
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.sun.proxy;
    
    import com.temp.ControlDB;
    import com.temp.ControlUI;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements ControlDB, ControlUI {
        private static Method m1;
        private static Method m4;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
             //继承父类就是为了使用父类的中的属性InvocationHandler
            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 void change() throws  {
            try {
               //回调invoke方法:super.h是因为父类才有InvocationHandler属性。
                super.h.invoke(this, m4, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        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 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);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m4 = Class.forName("com.temp.ControlUI").getMethod("change");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.temp.ControlDB").getMethod("add");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    

    代理类的父类:

    public class Proxy implements Serializable {
        private static final long serialVersionUID = -2222568056686623797L;
        private static final Class<?>[] constructorParams = new Class[]{InvocationHandler.class};
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
        //I am here
        protected InvocationHandler h;
        private static final Object key0 = new Object();
    
        private Proxy() {
        }
      ……
    }
    

    其他动态代理的实现技术:cglib,javassist,asm。

    相关文章

      网友评论

          本文标题:01-设计模式:JDK动态代理

          本文链接:https://www.haomeiwen.com/subject/naiooktx.html