转载

Java 中的动态代理

在 Java 中代理模式一般分为两种,静态代理和动态代理.

代理模式指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.

代理模式一般会有三个角色:

抽象角色:指代理角色和 真实角色对外提供的公共方法,一般为一个接口

真实角色:需要实现抽象角色接口,定义了真实角色所要实现的 业务逻辑,以便代理角色调用.也就是真正的业务逻辑.

代理角色:需要实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作.将统一的流程都控制到代理角色中处理.

而访问者不再访问真实角色,而是去访问代理角色。

静态代理

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

静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代理对象会出现扩展能力差的问题。

动态代理

指在使用时再创建代理类的实例

优点

只需要一个动态代理类,就可以解决创建多个静态代理类的问题,避免重复多余的代码

缺点

相比于静态代理,效率低.动态代理需要先通过 Java 反射机制,创建 Proxy 类来间接调用目标方法.

应用场景局限, 因为 Java 的单继承特征(每个代理类都继承了 Proxy 类),即只能针对接口创建代理类,不能针对类创建代理类.

在动态机制中,有两个重要的类和接口,一个是 InvocationHandler 接口,一个 Proxy 类,这两个是实现动态代理必须用到的.

InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。

public class DynamicProxy implements InvocationHandler {

    //持有的真实对象
    private Object factory;

    public Object getFactory() {
        return factory;
    }

    public void setFactory(Object factory) {
        this.factory = factory;
    }

    //获取到代理类实例
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(factory.getClass().getClassLoader()
                , factory.getClass().getInterfaces(), this);
    }

    //当方法被调用时,会调用 InvocationHandler 的 invoke 方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doSthAfter();
        Object result = method.invoke(factory, args);
        doSthBefore();
        return result;
    }

    private void doSthAfter() {
        System.out.println("调用之前进行操作");
    }

    private void doSthBefore() {
        System.out.println("调用之后进行操作");
    }
}

抽象代理接口

public class AbstractPart{
    void methodA()
}

真正实现业务逻辑的类

public class RealPart implements AbstractPart {
    @Override
    public void methodA() {
        System.out.println("真实实现!");
    }
}

使用动态代理

DynamicProxy dynamicProxy = new DynamicProxy();
dynamicProxy.setFactory(new RealPart());
AbstractPart proxyInstance = (AbstractPart) dynamicProxy.getProxyInstance();
proxyInstance.methodA();

动态代理实现原理

当我们创建一个动态代理时,最重要的一行代码是:

Proxy.newProxyInstance(factory.getClass().getClassLoader()
                , factory.getClass().getInterfaces(), this);

在newProxyInstance方法中,会先获取到动态创建的代理对象,然后获取构造器,创建实例对象.

Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});

在这个方法内部使用了 proxyClassCache.get 方法来获取代理类,通过这个方法我们可以知道 JDK 内部使用了某种缓存机制缓存了我们的代理类 class 对象,get 方法接受的参数是被代理类的类加载器和类实现的接口.

在 JDK 内部,会生成一个派生自 Proxy 的类

public final class $Proxy0 extends Proxy implements ICook {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } 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 methodA() 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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
  }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.caimuhao.examples.javaadvance.proxy.dynamic").getMethod("methodA", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

在这个类中,有我们代理对象的所有方法,当我们调用创建动态代理返回的对象的方法时,其实调用的是 h.invoke 方法,这个 h 对象就是我们在调用 Proxy.newProxyInstance 实例时,传入的 this 参数,也就是动态代理 中的 invoke 方法.这样我们就可以代理到其它类,在其它类方法执行前后加入一些我们自己的业务逻辑.

原文  http://caimuhao.com/2019/12/19/Java-Dynamic-Proxy/
正文到此结束
Loading...