Java 动态代理学习小结

最近由于闲来无事,看了一下动态代理的Java实现,现在在这边记录一下

首先我常见了一个demo类

class MyInvocationHandler implements InvocationHandler{
    // 目标对象
    private Object target;

    /**
     * 构造方法
     * @param target 目标对象
     */
    public MyInvocationHandler(Object target) {
        this.target = target;
    }


    /**
     * 执行目标对象的方法
     */
    @Override
    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() {
        //System.out.println(Thread.currentThread().getContextClassLoader());
 //System.out.println(Thread.currentThread().getContextClassLoader().getParent());
        //interface传入的原因是需要创建接口的代理类 this传入是需要毁掉这边的invoke方法
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(), this);

    }
}
public interface UserService {
    public abstract void add();
}

class UserServiceImpl  implements UserService{

    @Override
    public void add() {
        System.out.println("--------------------add---------------");
    }

}

public class Test {

    public static void main(String[] args) {
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 实例化目标对象
        UserService userService = new UserServiceImpl();

        // 实例化InvocationHandler
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);

        // 根据目标对象生成代理对象
        UserService proxy = (UserService) invocationHandler.getProxy();
        System.out.println(proxy.getClass().getName());
        // 调用代理对象的方法
        proxy.add();
    }
}

以上就是我测试的代码

这个动态代理,主要的难点还是在newProxyInstance方法里面,那在这个方法里面,主要做了什么事情呢?我们点进去看一下

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

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        //获取到的sm一般都是空的(什么情况下会是有的,现在还在验证当中)
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 产生一个代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //通过构造方法来获取Constructor
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //如果生成的代理类是私有的,那么需要通过反射设置成public
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //通过构造器的方式来生成代理对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

首先看下newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)传入的3个参数,

第一个是classLoader,不能传入不同的classLoader,因为她在后面有

if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }

检查是否可见,不同的classLoader有不同的命名空间,不能相互访问,父子关系的话,儿子能访问父亲的,而父亲不能访问儿子加载的类。

第二个是当前实现类的接口,用来通过这个接口创建代理类。

第三个是invocationHandler,用来回调invoke方法。

一般情况下sm是空的,所以这个权限的检查是不会走的,那么getProxyClass0做了什么事情呢?

1:通过key获取当前需要的代理类是否创建过,有的话就直接返回,没有的话就创建一个

2:如果没有的话,通过$Proxy+num创建一个代理类,默认保存在内存中,这个应用中代理类是自增长的,因为

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

proxyClassCache只会存在一个

 

当产生类代理类名称的时候,就会通过generateProxyClass方法产生代理类,这个代理类包括类Object的方法和我们接口定义的方法。我们可以通过设置

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

方法查看,产生的代理类是这样子的的,

public final class $Proxy0 extends Proxy implements UserService {
    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 add() 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", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.proxy.UserService").getMethod("add");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

那么最后记录一下方法执行的流程

1:通过newProxyInstance创建一个代理类,并传入MyInvocationHandler

2:调用proxy.add()方法的时候,实际上执行的是产生的代理类的add方面

3:代理类的add方法被调用后,调用super.h.invoke(this, m3, (Object[])null);这个h是我们传的MyInvocationHandler

4:执行MyInvocationHandler的invoke方法,打印出before

5:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 在目标对象的方法执行之前简单的打印一下
        System.out.println("------------------before------------------");

        // 执行目标对象的方法,这个targer是UserServiceImpl
        Object result = method.invoke(target, args);

        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");

        return result;
    }

执行方法中的invoke方法,这个方法会调用invoke0,从而调用到c代码

6:c代码会调用到我们的目标类UserServiceImpl中的add方法,至此调用完整结束。

 

附:创建对象的5种方法,

1:使用new关键字,会调用构造方法

2:使用Class类的newInstance方法,会调用构造方法

3:使用Constructor类的newInstance方法,会调用构造方法

4:使用clone方法,不会调用构造方法

5:使用反序列化,不会调用构造方法

 

最后指出一下,这篇文章只是我在阅读动态代理后的理解,如果有问题的地方,希望大家指出,我们共同进步,谢谢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值