美文网首页
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基础:反射

    反射注解动态代理相关阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 ...

  • 安卓反射和动态代理的应用

    提纲 java反射基础 反射在Android中的应用 Java动态代理 动态代理在Android的应用 java反...

  • 一文带你搞懂Java反射和动态代理

    分享 Java反射和动态代理

  • Java 动态代理

    前言 关于动态代理 JDK动态代理 CGLIB动态代理 区别 java动态代理是利用反射机制生成一个实现代理接口的...

  • Java反射机制详解(二)

    本篇文章继续介绍Java反射机制,不同的是侧重于介绍动态代理。动态代理是代理模式中的一种,是通过Java反射机制来...

  • Java反射机制总结(二)

    本篇文章继续介绍Java反射机制,不同的是侧重于介绍动态代理。动态代理是代理模式中的一种,是通过Java反射机制来...

  • 快速上手 Kotlin 开发系列之动态代理

    本节介绍 Kotlin 中没有反射的动态代理。 Java 中的动态代理 在讲 Kotlin 的动态代理之前先简单回...

  • Java反射与动态代理

    Java反射 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制 特点:...

  • Java反射与动态代理

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

  • 2021校招 复习总结

    笔记导航: JAVA: 泛型 反射和动态代理 注解 JAVA多线程 ReentrantLock,Volatile,...

网友评论

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

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