最近由于闲来无事,看了一下动态代理的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:使用反序列化,不会调用构造方法
最后指出一下,这篇文章只是我在阅读动态代理后的理解,如果有问题的地方,希望大家指出,我们共同进步,谢谢