java动态代理实现与原理详细分析这篇文章我感觉讲的很好,所以我也顺着作者的思路加上自己的理解再来撸一遍。
java中根据创建代理类的时间点,分为静态代理和动态代理
静态代理
代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息,过滤消息,把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
总结一句话就是:专业的事让专业的人干
小栗子
歌星商演,经纪人就充当一个代理人;前期接洽,面谈,商量出演费用,预付款等等事情都是由经纪人出面来处理,等到了商演的时候,经纪人告诉歌星,什么时间,什么地点要去唱个歌,之后又是经纪人负责尾款追收。
package com.principle.staticproxy;
public interface Star {
//面谈
void confer();
//签合同
void signContract();
//订票
void bookTicket();
//唱歌
void sing();
//收钱
void getMoney();
}
package com.principle.staticproxy;
public class RealStar implements Star{
@Override
public void confer() {
System.out.println("confer");
}
@Override
public void signContract() {
System.out.println("signContract");
}
@Override
public void bookTicket() {
System.out.println("bookTicket");
}
@Override
public void sing() {
System.out.println("sing");
}
@Override
public void getMoney() {
System.out.println("getMoney");
}
}
package com.principle.staticproxy;
public class ProxyStar implements Star {
private Star star;
public ProxyStar(Star star) {
super();
this.star = star;
}
@Override
public void confer() {
star.confer();
}
@Override
public void signContract() {
star.signContract();
}
@Override
public void bookTicket() {
star.bookTicket();
}
@Override
public void sing() {
star.sing();
}
@Override
public void getMoney() {
star.getMoney();
}
}
package com.principle.staticproxy;
public class Client {
public static void main(String[] args) {
Star reStar=new RealStar();
ProxyStar proxyStar=new ProxyStar(reStar);
proxyStar.confer();
proxyStar.signContract();
proxyStar.bookTicket();
proxyStar.sing();
proxyStar.getMoney();
}
}
静态代理就说这么多,今天主要说动态代理
动态代理
代理类在程序运行时创建的代理方式被成为动态代理。
我们上面静态代理的例子中,代理类是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
动态代理简单实现
- 创建一个InvocationHandler对象
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler handler=new MyInvocationHandler<Star>(realStar);
- 使用Proxy类的getProxyClass静态方法生成一个动态代理类proxy
Class<?> proxyClass = Proxy.getProxyClass(Star.class.getClassLoader(), new Class<?>[] {Star.class});
- 获得proxyClass中一个带InvocationHandler参数的构造器constructor
Constructor<?> constructor = StarProxy.getConstructor(InvocationHandler.class);
- 通过构造器constructor来创建一个动态实例proxy
Star proxy = (Star) cons.newInstance(handler);
就此,一个动态代理对象就创建完毕,当然,上面四个步骤可以通过Proxy类的newProxyInstances方法来简化:
Star realStar=new RealStar();
StarHandler handler=new StarHandler(realStar);
Star star=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class}, handler);
package com.principle.dynamicproxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star realStar=new RealStar();
StarHandler handler=new StarHandler(realStar);
Star star=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class}, handler);
star.sing();
}
}
我们先创建了委托类(RealStar)的实例,而这个委托类是实现了Star的接口得;然后实例化了一个InvocationHandler的实例,并将委托类(RealStar)的实例传过去了;再就获取到了委托类的代理star;最后调用代理类的sing方法;这里我有点迫不及待说出结论:
在创建代理类的时候,代理类的构造方法中是获取到InvocationHandler的实例对象,然后在对应的接口方法中,调用了InvocationHandler的invoke方法,并将Method和参数传了过去,InvocationHandler在调用invoke方法的时候(已经开始我们自己做主了),我们在该方法中拿到了对应的方法和参数,InvocationHandler中又有对应的委托类(RealStar)的对象,我们可以直接调用对应的方法。
总的来说就是当调用代理类的方法的时候,我们会调用InvocationHandler的invoke方法,在invoke方法中,我们会调用委托类(RealStar)的对应方法(自己处理),我们在这个方法(invoke)中可以拦截预处理,事后处理等等操作。
上面这个你可以先不看,或者也可以先简单的看一遍,不用深入追究,接下来我们看源码,然后再来看看这个结论就有感觉了。
package com.principle.dynamicproxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star realStar=new RealStar();
StarHandler handler=new StarHandler(realStar);
Star star=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class}, handler);
star.sing();
}
}
我们调用了Proxy.newProxyInstance方法;
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
Objects.requireNonNull(h);
//标记1
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.
*/
//标记2
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//标记3
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;
}
});
}
//标记4
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);
}
}
看看上面一共标记了四处代码
//标记1
final Class<?>[] intfs = interfaces.clone();
//标记2
Class<?> cl = getProxyClass0(loader, intfs);
//标记3
final Constructor<?> cons = cl.getConstructor(constructorParams);
//标记4
cons.newInstance(new Object[]{h});
- 获取到对应的接口类
- 获取到对应的代理类Class
- 获取到代理类的构造器
- 构造器实例化
主要就是获取到对应的代理类Class
可以看出,这个类的产生就是整个动态代理的关键,由于是动态生成的类文件,这里不具体进入分析如何产生的这个类文件,只需要知道这个类文件时缓存在java虚拟机中的,我们可以通过下面的方法将其打印到文件里面,一睹真容:
package com.principle.dynamicproxy;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Proxy;
import sun.misc.ProxyGenerator;
public class Client {
public static void main(String[] args) {
Star realStar=new RealStar();
StarHandler handler=new StarHandler(realStar);
Star star=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class}, handler);
star.sing();
System.out.println(star.getClass().getName());
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", RealStar.class.getInterfaces());
String path = "G:/java3/Base/src/com/principle/dynamicproxy/StarProxy.class";
File parent=new File("G:/java3/Base/src/com/principle/dynamicproxy");
if (!parent.exists()) {
parent.mkdirs();
}
try(FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
System.out.println("代理类class文件写入成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("写文件错误");
}
}
}
对这个class文件进行反编译,我们看看jdk为我们生成了什么样的内容:
package defpackage;
import com.principle.dynamicproxy.Star;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/* renamed from: $Proxy0 */
public final class C$Proxy0 extends Proxy implements Star {
private static Method m0;
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m5;
private static Method m6;
private static Method m7;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m6 = Class.forName("com.principle.dynamicproxy.Star").getMethod("signContract", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m5 = Class.forName("com.principle.dynamicproxy.Star").getMethod("getMoney", new Class[0]);
m7 = Class.forName("com.principle.dynamicproxy.Star").getMethod("bookTicket", new Class[0]);
m3 = Class.forName("com.principle.dynamicproxy.Star").getMethod("sing", new Class[0]);
m4 = Class.forName("com.principle.dynamicproxy.Star").getMethod("confer", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (Throwable e) {
throw new NoSuchMethodError(e.getMessage());
} catch (Throwable e2) {
throw new NoClassDefFoundError(e2.getMessage());
}
}
/**
*注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
*为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个
*被代理对象的实例,不禁会想难道是....? 没错,就是你想的那样。
*
*super(paramInvocationHandler),是调用父类Proxy的构造方法。
*父类持有:protected InvocationHandler h;
*Proxy构造方法:
* protected Proxy(InvocationHandler h) {
* Objects.requireNonNull(h);
* this.h = h;
* }
*
*/
public C$Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final void bookTicket() {
RuntimeException e;
try {
this.h.invoke(this, m7, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final void confer() {
RuntimeException e;
try {
this.h.invoke(this, m4, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final boolean equals(Object obj) {
RuntimeException e;
try {
return ((Boolean) this.h.invoke(this, m1, new Object[]{obj})).booleanValue();
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final void getMoney() {
RuntimeException e;
try {
this.h.invoke(this, m5, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final int hashCode() {
RuntimeException e;
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final void signContract() {
RuntimeException e;
try {
this.h.invoke(this, m6, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
/**
*
*这里调用代理对象的giveMoney方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
*this.h.invoke(this, m3, null);这里简单,明了。
*来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,
*再联系到InvacationHandler中的invoke方法。嗯,就是这样。
*/
public final void sing() {
RuntimeException e;
try {
this.h.invoke(this, m3, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
public final String toString() {
RuntimeException e;
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error e2) {
e = e2;
throw e;
} catch (RuntimeException e3) {
e = e3;
throw e;
} catch (Throwable th) {
UndeclaredThrowableException undeclaredThrowableException = new UndeclaredThrowableException(th);
}
}
}
可以看到上述代码和我们结论是一样的,上面的方法有点多,不过基本上内容都长一样的。
再把我们结论拿过来看看
在创建代理类的时候,代理类的构造方法中是获取到InvocationHandler的实例对象,然后在对应的接口方法中,调用了InvocationHandler的invoke方法,并将Method和参数传了过去,InvocationHandler在调用invoke方法的时候(已经开始我们自己做主了),我们在该方法中拿到了对应的方法和参数,InvocationHandler中又有对应的委托类(RealStar)的对象,我们可以直接调用对应的方法。
总的来说就是当调用代理类的方法的时候,我们会调用InvocationHandler的invoke方法,在invoke方法中,我们会调用委托类(RealStar)的对应方法(自己处理),我们在这个方法(invoke)中可以拦截预处理,事后处理等等操作。
我们可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能。
这里再次原作者表示感谢:java动态代理实现与原理详细分析
网友评论