美文网首页
Java反射与动态代理

Java反射与动态代理

作者: Boahui | 来源:发表于2020-11-02 11:15 被阅读0次

    代理模式

    代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活 中常见的中介。

    • 通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性
    • 通过代理对象对访问进行控制
      代理模式一般会有三个角色:
      代理
      抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口
      真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业 务逻辑在此。
      代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附 加自己的操作。将统一的流程控制都放到代理角色中处理!

    静态代理

    静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。一般 来说,被代理对象和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象也是可以的。

    /**
     *抽象 代理角色: 定义了服务的接口
     */
    public interface FindHouse {
        //找房服务
        void findHouseService();
    }
    
    /**
     * 代理对象:中介平台
     */
    public class Agent implements FindHouse {
    
        private final FindHouse findHouse;
    
        public Agent(FindHouse findHouse) {
            this.findHouse = findHouse;
        }
    
        //....前置处理
        public void before() {
            System.out.println("创建订单,找到空闲的中介");
        }
    
        //....后置处理
        public void after() {
            System.out.println("满意度调查");
        }
    
        @Override
        public void findHouseService() {
            before();
            findHouse.findHouseService();
            after();
        }
    }
    
    /**
     * 真实实现类: 中介小李
     */
    public class XiaoLi implements FindHouse {
    
    
        @Override
        public void findHouseService() {
            System.out.println("我是小李,我帮忙找到了一个100万元的别墅");
        }
    }
    
    /**
     *  实实现类:中介小王
     */
    public class XiaoWang implements FindHouse {
    
        @Override
        public void findHouseService() {
            System.out.println("我是小王,我找到了一个地铁口的200万的复式");
        }
    }
    
    public static void main(String[] args) throws Exception {
        //静态代理
        XiaoWang xiaoWang = new XiaoWang();
        XiaoLi xiaoLi = new XiaoLi();
    
        //代理平台分配小李帮忙找房
        Agent agent = new Agent(xiaoLi);
        agent.findHouseService();
    
        //代理平台分配小王帮忙找房
        agent.setFindHouse(xiaoWang);
        agent.findHouseService();
    

    ···
    运行代码


    image.png

    动态代理

    静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代 理对象会出现扩展能力差的问题。
    如果小王不仅会做房屋中介,还会洗车。

    /**
     * 洗车能力
     */
    public interface WashCar {
        void wash();
    }
    
    /**
     *  实实现类:中介小王,也会洗车
     */
    public class XiaoWang implements FindHouse, WashCar {
        @Override
        public void findHouseService() {
            System.out.println("我是小王,我找到了一个地铁口的200万的复式");
        }
        @Override
        public void wash() {
            System.out.println("我是小王,我可以洗车");
        }
    }
    

    在一对一代理情况下,需要再创建一个洗车代理类

    public class WashCarAgent implements WashCar {
        private WashCar washCar;
        public WashCarAgent(WashCar washCar) {
            this.washCar = washCar;
        }
        @Override
        public void wash() {
        }
    }
    

    一对多代理情况下,每增加一个功能就需要修改代理类增加一个变量,造成扩展性差

    /**
     * 代理对象:中介平台
     */
    public class Agent implements FindHouse,WashCar {
    
        private FindHouse findHouse;
        private WashCar washCar;//增加一个功能就需要修改代理类,来增加一个变量
    
        public Agent(FindHouse findHouse) {
            this.findHouse = findHouse;
        }
    
        public void setWashCar(WashCar washCar) {
            this.washCar = washCar;
        }
        @Override
        public void wash() {
            before();
            washCar.wash();
            after();
        }
    }
    

    JDK中为我们提供了生成动态代理类的方法

            //动态代理,JDK实现只能代理接口
            Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(),
                    new Class[]{FindHouse.class,WashCar.class}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                            return method.invoke(xiaoWang,objects);//传入小王
                        }
                    });
    
            FindHouse findHouse = (FindHouse) o;//将生成的代理对象强转为抽象接口
            findHouse.findHouseService();//调用方法
    
            WashCar wash = (WashCar) o;
            wash.wash();
    
    运行代码 如果传入的是小李,运行代码

    实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译 而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。

     String name = Api.class.getName()+"$Proxy0";
    //生成代理指定接口的Class数据
    byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{FindHouse.class,WashCar.class});
    FileOutputStream fos = new FileOutputStream("lib/" + name+".class"); fos.write(bytes);
    fos.close();
    
    从内存中导出生成的Class
    //生成Class的代码
    
    public final class FindHouse$Proxy0 extends Proxy implements FindHouse, WashCar {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m4;
        private static Method m0;
    
        public FindHouse$Proxy0(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 findHouseService() 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 wash() throws  {
            try {
                super.h.invoke(this, m4, (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"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.enjoy.lib.FindHouse").getMethod("findHouseService");
                m4 = Class.forName("com.enjoy.lib.WashCar").getMethod("wash");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    
    

    当我们调用这个动态代理对象的findHouseService方法时,我们可以发现,实际调用了

    super.h.invoke(this, m3, (Object[])null);
    

    其中的h我们看源码可以看到

    public class Proxy implements Serializable {
        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());
        protected InvocationHandler h;//就是我们在动态代理传入的InvocationHandler
        private static final Object key0 = new Object();
    
        private Proxy() {
        }
    
        protected Proxy(InvocationHandler var1) {
            Objects.requireNonNull(var1);
            this.h = var1;
        }
    

    其中的m3可以看到,就是我们抽象接口定义的方法

     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.enjoy.lib.FindHouse").getMethod("findHouseService");
                m4 = Class.forName("com.enjoy.lib.WashCar").getMethod("wash");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    

    相关文章

      网友评论

          本文标题:Java反射与动态代理

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