jdk动态代理解析

jdk动态代理通过jdk提供的Proxy类和InvocationHandler接口实现动态代理,但是jdk动态代理需要被代理的对象一定要实现了接口,更具体来说,实现的接口中的方法就是你想要代理的方法,在被代理类中不是实现接口中的方法的方法是不会被代理的。

下面来看一下InvocationHandler接口的源码:

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
下面是Proxy类的部分方法:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }
newProxyInstance方法就用来创建代理类的对象的,可以看到必须要有被代理对象的实现的接口,最重要的是最有一个参数InvocationHandler对象,实际这里我们传入的会是实现了InvocationHandler接口并且包含被代理对象的实例。

下面是我们实现了InvocationHandler接口的类:

public class MyInvocationHandler implements InvocationHandler {  
    // 目标对象   
    private Object target;  
    /** 
     * 构造方法 
     * @param target 目标对象  
     */  
    public MyInvocationHandler(Object target) {  
        super();  
        this.target = target;  
    }  
    /** 
     * 执行目标对象的方法 
     */  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        // 在目标对象的方法执行之前简单的打印一下  
        System.out.println("------------------before------------------");  
        // 执行目标对象的方法  
        Object result = method.invoke(target, args);  
        // 在目标对象的方法执行之后简单的打印一下  
        System.out.println("-------------------after------------------");  
        return result;  
    }  
    /** 
     * 获取目标对象的代理对象 
     * @return 代理对象 
     */  
    public Object getProxy() {  
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),   
                target.getClass().getInterfaces(), this);  
    }  
} 
把被代理对象最为构造函数参数传入到MyInvocationHandler类中,主要是为了要在invoke方法中使用,我们现在看invoke方法:

使用java的反射机制通过method.invoke调用被代理对象的method,在invoke方法上下可以加入增强功能,比如可以加上一些日志记录,事务控制功能等等

下面再看我们自定义的getProxy方法,可以获得代理类实例对象,在newProxyInstance方法中出入了this,那么传入的invocationHandler对象是怎样能够生成代理类的呢?
下面来看一下Proxy类的

 /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }


下面是ProxyClassFactory代理类工场,生成代理类的地方。下面是这个类怎样为代理类拼接名字的:

 // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();


 /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            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());
            }
里面会使用java1.5之后提供的原子操作类中的AutomicLong,能够通过CAS算法硬件支持来实现++自增原子操作。代理类的名字一般拼接成这样的$Proxy1

通过ProxyGenrator的genrateProxyClass方法生成类文件定义的字符串的byte数组(这里我没有去看方法的源码),然后作为参数传递给defineClass0来在本地硬盘上生成代理类,然后并通过类加载器把类加载到jvm中,并把Class对象返回,这样就得到了代理类的Class对象了。

我们可以直接调用ProxyGenerator的generateProxyClass方法来获取代理类的字节码byte数组,然后写到自己指定的硬盘地址,就能找到代理类的class文件了,然后通过反编译工具查看源码:

 // 获取代理类的字节码  
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", UserServiceImpl.class.getInterfaces());  

下面来看一下一个例子,看看代理类具体时什么样的:


public final class $Proxy11 extends Proxy  
    implements UserService  
{  
  
    // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例  
    public $Proxy11(InvocationHandler invocationhandler)  
    {  
        super(invocationhandler);  
    }  
  
    public final boolean equals(Object obj)  
    {  
        try  
        {  
            return ((Boolean)super.h.invoke(this, m1, new Object[] {  
                obj  
            })).booleanValue();  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    /** 
     * 这个方法是关键部分 
     */  
    public final void add()  
    {  
        try  
        {  
            // 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了  
            super.h.invoke(this, m3, null);  
            return;  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final int hashCode()  
    {  
        try  
        {  
            return ((Integer)super.h.invoke(this, m0, null)).intValue();  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final String toString()  
    {  
        try  
        {  
            return (String)super.h.invoke(this, m2, null);  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    private static Method m1;  
    private static Method m3;  
    private static Method m0;  
    private static Method m2;  
  
    // 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法  
    static   
    {  
        try  
        {  
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
                Class.forName("java.lang.Object")  
            });  
            m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
        }  
        catch(NoSuchMethodException nosuchmethodexception)  
        {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        }  
        catch(ClassNotFoundException classnotfoundexception)  
        {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }  
}  

从这里可以看到Proxy类把invocationHandler对象作为代理类的构造方法参数传入,并且通过抽取被代理类实现的接口中包含的方法,在静态代码块儿中实例化包含的所有method对象,然后在这些method对象对应的方法定义中调用invocationHandler对象的invoke方法,把对应的method当做参数,其实还是真正的被代理类用反射执行对应的方法。

说到底,还是Proxy类中生成代理类的字节码内容是自定义的,这样可以巧妙的生成上面类的定义,可以实现方法相对应,并且在类加载到内存后,在显示使用代理类时初始化,执行静态代码块儿实例化method对象。

根据提供的生成的代理类,类加载器,根据传入的代理类的字节码数组返回代理类的Class对象

 private static native Class defineClass0(ClassLoader loader, String name,
                                             byte[] b, int off, int len);

总结

简单的分析了一下JDK动态代理类的创建过程,JDK动态代理必须要实现接口,这是一个局限点,当我们需要被代理的对象没有实现接口就无法使用了,那么就需要使用cglib来生成代理类了。后面会介绍一下cglib生成代理类的原理。





你可能感兴趣的:(JDK动态代理)