Java反射与动态代理

2020-11-02  本文已影响0人  Boahui

代理模式

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

静态代理

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

/**
 *抽象 代理角色: 定义了服务的接口
 */
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());
        }
    }
上一篇下一篇

猜你喜欢

热点阅读