Java动态代理简析原理

说下Java动态代理,Spring的AOP就是基于Java的动态代理实现的。动态代理用到的几个类和接口,Proxy提供了一些静态的创建动态代理Class的方法。InvocationHandler接口,代理实现必须实现的接口。

一个简单的例子:

/**
 * HelloInterface 接口,定义了一个sayHello的方法
 */
interface  HelloInterface{
    public void sayHello();
}

/**
 * HelloInterface的一个实现类
 */
class HelloImpl implements HelloInterface{

    @Override
    public void sayHello() {
        System.out.println("Hello!");
    }
}

/**
 * 真正的代理类执行者
 */
class HelloHandler implements InvocationHandler{
    HelloInterface helloInterface;
    public HelloHandler(HelloInterface helloInterface){
        this.helloInterface = helloInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before exec method: "+ method.getName());
        method.invoke(helloInterface,args);
        System.out.println("after exec method: "+ method.getName());
        return null;
    }
}

一个简单的测试:

public static void main(String[] args) {
   HelloInterface helloInterface = (HelloInterface) Proxy.newProxyInstance(
           HelloImpl.class.getClassLoader(),
           HelloImpl.class.getInterfaces(),
           new  HelloHandler( new HelloImpl()));
    System.out.println(helloInterface.getClass().getName());
    helloInterface.sayHello();
}

输出:

$Proxy0
before exec method: sayHello
Hello!
after exec method: sayHello

Proxy.newProxyInstance 返回的对象名称是$Proxy0。这个怎么能转成HelloInterface呢?

分析下Proxy.newProxyInstance, 首先是3个参数,源码中的,挺简单不翻译了

 * @param   loader the class loader to define the proxy class
 * @param   interfaces the list of interfaces for the proxy class
 *          to implement
 * @param   h the invocation handler to dispatch method invocations to

下面就是简化后的代码:

public static Object newProxyInstance(ClassLoader loader,
                                      Class[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class[] intfs = interfaces.clone();
 
    /*
     * 在缓存中查找,如果找不到就新建个代理类
     */
    Class cl = getProxyClass0(loader, intfs);

    /*
     * 调用代理类生成新的实例
     */
    final Constructor cons = cl.getConstructor(constructorParams);
    final InvocationHandler ih = h;
        
    return cons.newInstance(new Object[]{h});
    
}

调用方法getProxyClass0 获得Class 对象,这个方法先从proxyClassCache 获得,如果不存在通过ProxyClassFactory 来创建。实际上就是通过生成Class对象的字节数组,最后转成Class对象。
来看具体代码(删除了一些验证的代码)

    @Override
    public Class apply(ClassLoader loader, Class[] interfaces) {

        Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);

        String proxyPkg = null;     // package to define proxy class in
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

        /*
         * 记录非公有的代理接口的包名,并且所有的非公有的代理接口必须在同一个包中。
         */
        for (Class intf : interfaces) {
            int flags = intf.getModifiers();
            if (!Modifier.isPublic(flags)) {
                accessFlags = Modifier.FINAL;
                String name = intf.getName();
                int n = name.lastIndexOf('.');
                String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                if (proxyPkg == null) {
                    proxyPkg = pkg;
                } else if (!pkg.equals(proxyPkg)) {
                    throw new IllegalArgumentException(
                        "non-public interfaces from different packages");
                }
            }
        }

        if (proxyPkg == null) {
            // 如果存在非公有的代理接口包,就用这个,如果都是公有的,就用默认的包com.sun.proxy
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }

        /*
         * 此处就是生成$Proxy0的Class的名字
         */
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg + proxyClassNamePrefix + num;

        /*
         * 生成Class的字节码,通过defineClass0转成Class对象
         */
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        try {
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            /*
             * A ClassFormatError here means that (barring bugs in the
             * proxy class generation code) there was some other
             * invalid aspect of the arguments supplied to the proxy
             * class creation (such as virtual machine limitations
             * exceeded).
             */
            throw new IllegalArgumentException(e.toString());
        }
    }

如果细看ProxyGenerator.generateProxyClass会发现$Proxy0 其实实现了代理接口,可以解释了Proxy.newProxyInstance 返回的对象为什么能转成代理接口。如果想看生成的$Proxy0生成的class,可以添加代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");来保存$Proxy0.class.
下面来看看生成的代码:

final class $Proxy0 extends Proxy implements HelloInterface {
private static Method m1;
private static Method m3;
private static Method m2;
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});
    } catch (RuntimeException | Error var3) {
        throw var3;
    } catch (Throwable var4) {
        throw new UndeclaredThrowableException(var4);
    }
}

public final void sayHello() throws  {
    try {
        super.h.invoke(this, m3, (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 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"));
        m3 = Class.forName("test.proxy.HelloInterface").getMethod("sayHello");
        m2 = Class.forName("java.lang.Object").getMethod("toString");
        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动态代理简析原理_第1张图片
奔跑蜗牛

你可能感兴趣的:(Java动态代理简析原理)