前言 |
今天一定要把这一篇博客补上,前段时间看了看动态代理的jdk方式如何实现,用起来简单,但是jdk中的实现就不那么容易了~~
代理模式的特点 |
- 有执行者、被代理者两种角色
- 这件事一定要做,自己不想做,或者没有时间做
- 执行者需要获取被代理人的资料
例子:取快递、中介、媒人等
代理模式的应用小例子——Celine取快递 |
celine的快递到了,但是她去公司上班了,所以她爸帮她取得快递。从这个例子中,我们抽象出了被代理人(celine),代理人(她爸爸),接口(取快递)
(1) 接口
public interface Receive {
public void Receive();
}
(2)celine
/**
* 被代理类
*/
public class Celine implements Receive {
@Override
public void Receive() {
System.out.println("Celine在上班,没有办法取快递");
}
}
(3)代理类
/**
* 代理类需要实现InvocationHandler接口,并且重写invoke方法,其中的method.invoke(target, args)就是celine具体实现接口的方法
*/
public class CelineFather implements InvocationHandler {
private Object target;
public CelineFather(Object target) {
super();
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(target, args);
System.out.println("celine她爸取得快递");
return null;
}
}
(4)测试类
public class TestJdkDynamicProxy {
public static void main(String[] args){
Celine celine=new Celine();
Class celineClass=celine.getClass();
//通过newProxyInstance生成代理对象
Receive Receiver = (Receive)Proxy.newProxyInstance(celineClass.getClassLoader(), celineClass.getInterfaces(),
new CelineFather(celine));
//实际调用的是代理类中的invoke方法
Receiver.Receive();
}
}
JDK实现原理 |
- 拿到被代理对象的引用,然后获取他的接口
- jdk代理重新生成一个类,同时实现代理对象所实现的接口(所以jdk的动态代理必须有接口)
- 拿到对象的引用
- 重新动态生成一个class字节码
- 重新编译
jdk源码中几个重要的方法 |
首先提出几个疑问:
1.为什么最后真正实现的是代理类的invoke方法?
2.为什么newProxyInstance返回值要强转成接口的实例?
3.newProxyInstance没有转成接口类之前是什么?
我们从newProxyInstance这个方法入手,首先这个方法传入了三个参数,分别是Celine的类加载器,Celine实现的接口数组,CelineFather的对象
这个方法为我们做了三件比较重要的事情:
1、生成代理类
2、获得代理类的构造函数
3、根据构造函数实例化代理类(生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法 )
@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();
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 {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获得代理类的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法
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);
}
}
getProxyClass0(loader, intfs)这个方法是最为重要的,他会生成一个$Proxy0的类,经过反编译,我们看看这个类是什么样子的(下边代码来源于网络,我没有下载反编译工具,所以就在网上找了一个)
这个类他会实现我们的被代理类中所有的方法,最为重要的是其中的super.h.invoke(this, m3, null); 方法,这也就是为什么调用invoke方法实现的确实代理类的invoke方法,而且invoke方法会调用Celine的receive方法,第二个参数m3就是被代理类对象的receive的方法,这也解决了我们的三个疑问
import dynamic.proxy.UserService;
import java.lang.reflect.*;
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());
}
}
}