Java中从1.3中引入Proxy,实现接口的动态代理。JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。本文从简单例子入手,通过分析源码看看其内部实现原理,使用的是JDK 1.8。 ####简单运用 使用动态代理主要涉及接口InvocationHandler,以及Proxy类。 通过动态代理实现对接口中方法调用前后进行拦截处理
创建要代理的接口,以及一个实现类。
package com.proxy;
/**
*
* 要代理的接口<br/>
*
* @version
*/
public interface PeopleService {
public void sayHello();
public void printName(String name);
}
简单实现类EnglishService
package com.proxy;
/**
*
* 注释内容<br/>
*
*
* @version
*/
public class EnglishService implements PeopleService {
@Override
public void sayHello() {
System.out.println("Hi~");
}
@Override
public void printName(String name) {
System.err.println("Your name:" + name);
}
}
定义自己的InvocationHandler
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* 注释内容<br/>
*
* @version
*/
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用前打印
System.err.println("------begin----------");
method.invoke(target, args);
System.err.println("------end----------");
return null;
}
}
编写测试类
package com.test;
import java.lang.reflect.Proxy;
import org.testng.annotations.Test;
import com.proxy.EnglishService;
import com.proxy.MyInvocationHandler;
import com.proxy.PeopleService;
public class MyTest {
@Test
public void proxyTest() {
MyInvocationHandler handler = new MyInvocationHandler(new EnglishService());
PeopleService proxyService = (PeopleService) Proxy.newProxyInstance(MyTest.class.getClassLoader(), new Class[] { PeopleService.class }, handler);
proxyService.sayHello();
}
}
运行结果:
成功实现对接口方法的前后拦截。JDK内部究竟怎么实现代理的?什么时候调用MyInvocationHandler 的invoke方法?下面分析原理: 看代理类获取时,关键代码为Proxy.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();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 代理类生成的核心代码
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* 通过传入的InvocationHander调用其构造器获取接口实例
*/
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;
}
});
}
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方法:
//生成一个代理类,在调用该方法前,必须调用checkProxyAccess校验权限
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
//代理接口数限制
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//如果由给定的加载器实现给定的接口定义的代理类存在,返回缓存;否则,它将通过ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
这里只是用WeakCache做了proxy classes缓存:
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
通过KeyFactory和ProxyClassFactory作为WeakCache的键和值,它们都是Proxy的内部静态类,都实现了BiFunction接口。继续查看WeakCache的get方法可看到,proxy class的生成最终调用了ProxyClassFactory的apply方法。关于WeakCache实现缓存的代码这里不多做描述。下面重点看ProxyClassFactory的定义和appy方法的实现:
//通过ClassLoader和接口列表,生成和定义一个proxy class
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有代理类的命名前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 一个唯一的number作为proxy class的名称标识
private static final AtomicLong nextUniqueNumber = new AtomicLong();
//proxy class生成方法
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
//确认类加载器解析了这个名字的接口到相同的Class对象。
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
//确认代理的Class是接口,从这可看出JDK动态代理的劣势
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//接口重复校验
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // 定义proxy class 所在的包
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
//记录所有non-public的 proxy interfaces都在同一个package中
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果没有non-public的interfaces,默认包为com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
//最终大概名字为:com.sun.proxy.$Proxy1
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成特殊的proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return 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());
}
}
}
调用ProxyGenerator.generateProxyClass生成proxy class, ProxyGenerator在sun.misc包中,未提供源码,我们通过反编译可以看到:
public static byte[] generateProxyClass(String arg, Class<?>[] arg0, int arg1) {
ProxyGenerator arg2 = new ProxyGenerator(arg, arg0, arg1);
byte[] arg3 = arg2.generateClassFile();
if(saveGeneratedFiles) {
AccessController.doPrivileged(new 1(arg, arg3));
}
return arg3;
}
//私有构造器
private ProxyGenerator(String arg0, Class<?>[] arg1, int arg2) {
this.className = arg0;
this.interfaces = arg1;
this.accessFlags = arg2;
}
下面是generateClassFile方法:
private byte[] generateClassFile() {
//添加从 Object基类中继承的方法
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
//添加接口中的方法实现
Class[] arg0 = this.interfaces;
int arg1 = arg0.length;
int arg2;
Class arg3;
for (arg2 = 0; arg2 < arg1; ++arg2) {
arg3 = arg0[arg2];
Method[] arg4 = arg3.getMethods();
int arg5 = arg4.length;
for (int arg6 = 0; arg6 < arg5; ++arg6) {
Method arg7 = arg4[arg6];
this.addProxyMethod(arg7, arg3);
}
}
Iterator arg10 = this.proxyMethods.values().iterator();
List arg11;
while (arg10.hasNext()) {
arg11 = (List) arg10.next();
checkReturnTypes(arg11);
}
Iterator arg14;
try {
//构造方法
this.methods.add(this.generateConstructor());
arg10 = this.proxyMethods.values().iterator();
while (arg10.hasNext()) {
arg11 = (List) arg10.next();
arg14 = arg11.iterator();
while (arg14.hasNext()) {
ProxyMethod arg15 = (ProxyMethod) arg14.next();
this.fields.add(new FieldInfo(this, arg15.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(ProxyMethod.access$100(arg15));
}
}
this.methods.add(this.generateStaticInitializer());
} catch (IOException arg9) {
throw new InternalError("unexpected I/O Exception", arg9);
}
if (this.methods.size() > '') {
throw new IllegalArgumentException("method limit exceeded");
} else if (this.fields.size() > '') {
throw new IllegalArgumentException("field limit exceeded");
} else {
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
arg0 = this.interfaces;
arg1 = arg0.length;
for (arg2 = 0; arg2 < arg1; ++arg2) {
arg3 = arg0[arg2];
this.cp.getClass(dotToSlash(arg3.getName()));
}
this.cp.setReadOnly();
//生成文件
ByteArrayOutputStream arg12 = new ByteArrayOutputStream();
DataOutputStream arg13 = new DataOutputStream(arg12);
try {
arg13.writeInt(-889275714);
arg13.writeShort(0);
arg13.writeShort(49);
this.cp.write(arg13);
arg13.writeShort(this.accessFlags);
arg13.writeShort(this.cp.getClass(dotToSlash(this.className)));
arg13.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
arg13.writeShort(this.interfaces.length);
Class[] arg16 = this.interfaces;
int arg17 = arg16.length;
for (int arg18 = 0; arg18 < arg17; ++arg18) {
Class arg21 = arg16[arg18];
arg13.writeShort(this.cp.getClass(dotToSlash(arg21.getName())));
}
arg13.writeShort(this.fields.size());
arg14 = this.fields.iterator();
while (arg14.hasNext()) {
FieldInfo arg19 = (FieldInfo) arg14.next();
arg19.write(arg13);
}
arg13.writeShort(this.methods.size());
arg14 = this.methods.iterator();
while (arg14.hasNext()) {
MethodInfo arg20 = (MethodInfo) arg14.next();
arg20.write(arg13);
}
arg13.writeShort(0);
//返回字节流
return arg12.toByteArray();
} catch (IOException arg8) {
throw new InternalError("unexpected I/O Exception", arg8);
}
}
}
看到这,我们可以很清晰的知道Proxy class是在什么时候生成的,以及这个class的大概面目(有Object的基本hashCode、equals、toString方法;有构造方法,有接口的实现方法)。我们回到generateProxyClass方法,看到生成后处理(上面有代码,不做重复):对saveGeneratedFiles进行判断,为真的话进行AccessController.doPrivileged(new 1(arg, arg3)),查看资料是将生成的proxy class文件存在硬盘,未测试,不做说明。其中saveGeneratedFiles是一个系统变量,可以通过 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");进行设置,默认false。
private static final boolean saveGeneratedFiles = ((Boolean) AccessController
.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
知道调用原理,我们可以使用ProxyGenerator.generateProxyClass生成文件看看具体内容,编写测试方法:
public static void main(String[] args) {
String fileName = "$Proxy11";
// 获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass(fileName, EnglishService.class.getInterfaces());
FileOutputStream out = null;
String outFilePath = "yourpath" + fileName + ".class";
try {
out = new FileOutputStream(outFilePath);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后在指定路径下生成$Proxy11.class文件,反编译查看内容:
import com.proxy.api.PeopleService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
* 生成的类继承了Proxy,实现了要代理的接口PeopleService
*
*/
public final class $Proxy11
extends Proxy
implements PeopleService
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $proxy11(InvocationHandler paramInvocationHandler)
{
//调用基类Proxy的构造器
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 sayHello()
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void printName(String paramString)
{
try
{
this.h.invoke(this, m4, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
//利用反射生成5个方法,包括Object中的equals、toString、hashCode以及PeopleService中的sayHello和printName
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.proxy.api.PeopleService").getMethod("sayHello", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.proxy.api.PeopleService").getMethod("printName", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
java.lang.reflect中Proxy有以下代码:
/**
* the invocation handler for this proxy instance.
* @serial
*/
//直接子类可使用
protected InvocationHandler h;
/**
* Constructs a new {@code Proxy} instance from a subclass
* (typically, a dynamic proxy class) with the specified value
* for its invocation handler.
*
* @param h the invocation handler for this proxy instance
*
* @throws NullPointerException if the given invocation handler, {@code h},
* is {@code null}.
*/
//直接子类可调用
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
现在再看生成的$Proxy11.class反编译的java代码中,调用sayHello时会this.h.invoke(this, m3, null);调用Proxy类中InvocationHandler的invoke方法,所以,文章开头我们的小例子中:
PeopleService proxyService = (PeopleService) Proxy.newProxyInstance(MyTest.class.getClassLoader(), new Class[] { PeopleService.class }, handler);
proxyService.sayHello();
proxyService.sayHello()的结果是走的MyInvocationHandler的invoke方法,也就一目了然。
总结
因为生成的proxy class中,继承了Proxy类,实现了需要代理的接口,而Java中是单继承,多实现的处理方式,也就解释了JDK动态代理中只能代理接口的原因了。
注意
关于通过设置 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 环境变量使得proxy class生成文件存在disk中,我未测试通过,对这一块,持保留意见
参考
特别感谢以下网友博客提供的帮助: http://rejoy.iteye.com/blog/1627405 http://blog.csdn.net/mhmyqn/article/details/48474815