JDK动态代理

JDK动态代理的理解可以帮助我们很好的去理解Spring的AOP思想以及实现。废话不多说,先来个小例子。

1. 定义一个接口,因为JDK动态代理代理的是实现了接口的类

public interface PersonalTest {

    void printString(String str);
    
    void printString1(String str);

}

2.其实现类

public class PersonalTestImpl implements PersonalTest {

    @Override
    public void printString(String str) {
        System.out.println("print value = "+str);
    }

    @Override
    public void printString1(String str) {
        System.out.println("print value1 = "+str);
    }
}
3.要能使用代理对象,需要实现InvocationHandle接口
public class PersonalInvocation implements InvocationHandler {

    private Object target;


    public PersonalInvocation(Object target) {
        this.target = target;
    }

    /**
     * 代理类执行
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invocation");

        //调用目标类的方法
        Object returnVal = method.invoke(target,args);

        System.out.println("after invocation");

        return returnVal;
    }

    /**
     * 获取代理对象
     * @return
     */
    public Object getTargetProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }

}

4.测试main

public class TestA {
    public static void main(String[] args) throws Exception{

        PersonalTest p = new PersonalTestImpl();

        PersonalInvocation in = new PersonalInvocation(p);

        PersonalTest proxy = (PersonalTest) in.getTargetProxy();

        proxy.printString("hello!!!");

        proxy.printString1("hello???");
    }
}
5.输出
before invocation
print value = hello!!!
after invocation
before invocation
print value1 = hello???
after invocation

以上是一个简单的测试用例,我觉得一开始接触的人会有疑问?至少我一直都是有点糊里糊涂的,至少没有一个明确的结论。

1.为什么proxy在调用printString的时候会执行到invoke方法上去?也可以这么想,invoke是谁在调用?

2.InvocationHandler中invoke方法内的第一个参数proxy是什么?

带着疑问我们可以做一些简单的测试:

public class TestA {
    public static void main(String[] args) throws Exception{

        PersonalTest p = new PersonalTestImpl();

        PersonalInvocation in = new PersonalInvocation(p);

        PersonalTest proxy = (PersonalTest) in.getTargetProxy();

        System.out.print("是不是Proxy的实例: ");
        System.out.println(proxy instanceof Proxy);
        System.out.println("Class是什么: "+proxy.getClass().toString());
        System.out.println("继承的父类是什么: "+proxy.getClass().getSuperclass());
        Class<?>[] t = proxy.getClass().getInterfaces();
        System.out.print("实现的接口是什么: ");
        for(Class<?> each: t){
            System.out.print(each.getName()+", ");
        }
        System.out.println();
        Method[] method=proxy.getClass().getDeclaredMethods();
        System.out.print("内部方法是什么: ");
        for(Method m:method){
            System.out.print(m.getName()+", ");
        }
    }
}
是不是Proxy的实例: true
Class是什么: class com.sun.proxy.$Proxy0
继承的父类是什么: class java.lang.reflect.Proxy
实现的接口是什么: com.wayne.sam.PersonalTest, 
内部方法是什么: equals, toString, hashCode, printString, printString1, 

上面是一些简单的测试,应该能从中获取一些感想吧,有没有发现Class是一个procy.$Proxy0的玩意儿,这玩意儿是怎么出来的?接下来我们去内部看下源码,最后再分析上面两个问题。

1. 我么从PersonalInvocation中的getProxy方法入手newProxyInstance,它最终生成的是代理类的一个实例对象,用于最后的操作,也就是上例中的printString操作。

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

        /*
         * Look up or generate the designated proxy class.
         */
        //寻找或者生成代理对象,主要的操作在这里面
        Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //调用代理对象的构造方法(也就是$Proxy0的构造方法,参数是InvocationHandler h)
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            SecurityManager sm = System.getSecurityManager();
            if (sm != null && Proxy.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 {
                //生成代理类的实例,参数是我们自己的PersonalInvocation
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }
2.简化了一些无关紧要的代码,基本的策略就是生成代理对象的字节码,然后最终构造出代理对象的实例返回。
private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
      ...
        //代理对象对应的Class对象
        Class<?> proxyClass = null;

        /* collect interface names to use as key for proxy class cache */
        String[] interfaceNames = new String[interfaces.length];

        // for detecting duplicates
        Set<Class<?>> interfaceSet = new HashSet<>();
        //变量目标类所实现的接口
        for (int i = 0; i < interfaces.length; i++) {
            /*
             * Verify that the class loader resolves the name of this
             * interface to the same Class object.
             */
            //接口名称
            String interfaceName = interfaces[i].getName();
            Class<?> interfaceClass = null;
            try {
                //反射拿到接口
                interfaceClass = Class.forName(interfaceName, false, loader);
            } catch (ClassNotFoundException e) {
            }
            //...验证操作

            //将接口的Class对象放入Set
            interfaceSet.add(interfaceClass);

            interfaceNames[i] = interfaceName;
        }

        /*
         * Using string representations of the proxy interfaces as
         * keys in the proxy class cache (instead of their Class
         * objects) is sufficient because we require the proxy
         * interfaces to be resolvable by name through the supplied
         * class loader, and it has the advantage that using a string
         * representation of a class makes for an implicit weak
         * reference to the class.
         */
        List<String> key = Arrays.asList(interfaceNames);

        /*
         * Find or create the proxy class cache for the class loader.
         */
        Map<List<String>, Object> cache;
        synchronized (loaderToCache) {
            //先从缓存中获取
            cache = loaderToCache.get(loader);
            if (cache == null) {
                cache = new HashMap<>();
                loaderToCache.put(loader, cache);
            }
        }
        synchronized (cache) {
            do {
                //从Cache中获取
                Object value = cache.get(key);
                if (value instanceof Reference) {
                    proxyClass = (Class<?>) ((Reference) value).get();
                }
                if (proxyClass != null) {
                    return proxyClass;
                } else if (value == pendingGenerationMarker) {
                    try {
                        cache.wait();
                    } catch (InterruptedException e) {
                    }
                    continue;
                } else {
                    cache.put(key, pendingGenerationMarker);
                    break;
                }
            } while (true);
        }

        try {
            //...准备一些代理对象的名称和包名等等信息

                /*
                 * Generate the specified proxy class. 生成代理对象字节码
                 */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces);
            try {
                //根据代理类的字节码生成代理类的实例
                proxyClass = 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());
                //...
                return proxyClass;
            }
3.生成代理对象的字节码,用于返回代理对象的实例
public static byte[] generateProxyClass(final String var0, Class[] var1) {
        ProxyGenerator var2 = new ProxyGenerator(var0, var1);
        //动态生成字节码,
        final byte[] var3 = var2.generateClassFile();
        if (saveGeneratedFiles) {  //如果是true的话会生成字节码到本地去
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        FileOutputStream var1 = new FileOutputStream(ProxyGenerator.dotToSlash(var0) + ".class");
                        var1.write(var3);
                        var1.close();
                        return null;
                    } catch (IOException var2) {
                        throw new InternalError("I/O exception saving generated file: " + var2);
                    }
                }
            });
        }
        //返回代理类的字节码
        return var3;
    }
4.生成的代理类反编译出来的效果,答案都在里面
//有没有发现生成的代理类继承的是Procy类,实现了我们定义的接口PersonalTest
public final class $Proxy11 extends Proxy implements PersonalTest
{
    private static Method m1;
    private static Method m4;
    private static Method m3;
    private static Method m0;
    private static Method m2;

    public $Proxy11(InvocationHandler paramInvocationHandler)
    {
        //构造方法的入参就是InvocationHandler,记得上面的代码不???
        super(paramInvocationHandler);
    }

    public final boolean equals(Object paramObject)
    {
        try
        {
            return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    //代理类里面实现了这个接口
    public final void printString(String paramString)
    {
        try
        {
            //底层调用的是h(h就是InvocationHandler接口),
            //又因为我们实现了这个接口,所以本质上是调用我们自定义InvocationHandler中的invoke方法
            //参数解析 this --> 当年代理类自身
            //        m4 --> 可以从下面得知是printString这个方法
            this.h.invoke(this, m4, new Object[] { paramString });
            return;
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void printString1(String paramString)
            throws
    {
        try
        {
            this.h.invoke(this, m3, new Object[] { paramString });
            return;
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final int hashCode()
            throws
    {
        try
        {
            return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String toString()
            throws
    {
        try
        {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static
    {
        try
        {
            //在这边进行的静态初始化,都在这儿了,看见
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
            m4 = Class.forName("com.wayne.sam.PersonalTest").getMethod("printString", new Class[] { Class.forName("java.lang.String") });
            m3 = Class.forName("com.wayne.sam.PersonalTest").getMethod("printString1", new Class[] { Class.forName("java.lang.String") });
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }

现在我觉得可以回答上面两个问题了:

1.为什么proxy在调用printString的时候会执行到invoke方法上去?也可以这么想,invoke是谁在调用?

-->invoke其实就是代理对象在调用,因为最终生成的$Proxy0实例强制转换成了PersonalTest,而我们调用PersonalTest的对代理对象proxy的printString方法时,会去调用$Proxy0内的invoke方法,进而调用Proxy中Invocation的invoke方法,从而最终调用到PersonalInvocation中的invoke方法。

2.InvocationHandler中invoke方法内的第一个参数proxy是什么?

-->代理对象本身,但是源码里并没有使用,估计是留着如果要使用代理对象的一些信息。

增加一个问题:为什么JDK动态代理只能代理实现了接口的类

-->有没有发现最终生成的$Proxy0这个代理类呢?它继承了Proxy,没错,Java只能允许单继承,而允许多实现接口,就是这么简单。换句话说,它没法再去继承另外一个类了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值