动态代理的使用
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
创建某一接口 Foo 的代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
来看一个具体的列子使用
业务代码
public interface IPersonService {
void sayHello();
}
public class PersonServiceImpl implements IPersonService {
@Override
public void sayHello() {
System.out.println("hello to you");
}
}
增强代码实现
public class InvocationHandlerImpl implements InvocationHandler {
private IPersonService service;
public InvocationHandlerImpl(IPersonService service) {
this.service = service;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==>");
System.out.println("====>");
Object invoke = method.invoke(service, args);
System.out.println("======>");
System.out.println("========>");
return invoke;
}
}
测试
public class Test {
public static void main(String[] args) throws Exception {
IPersonService service = new PersonServiceImpl();
InvocationHandler h = new InvocationHandlerImpl(service);
Class<?> proxyClass = Proxy.getProxyClass(service.getClass().getClassLoader(), service.getClass().getInterfaces());
IPersonService proxyService = (IPersonService) proxyClass.getConstructor(InvocationHandler.class).newInstance(h);
proxyService.sayHello();
}
}
输出结果,增强代理成功
==>
====>
hello to you
======>
========>
深度分析
分析测试方法
IPersonService service = new PersonServiceImpl();
InvocationHandler h = new InvocationHandlerImpl(service);
Class<?> proxyClass = Proxy.getProxyClass(service.getClass().getClassLoader(), service.getClass().getInterfaces());
IPersonService proxyService = (IPersonService) proxyClass.getConstructor(InvocationHandler.class).newInstance(h);
proxyService.sayHello();
从测试代码中我们可以看出,调用代码proxyService.sayHello()
中的对象proxyService
,是第三行代码中的proxyClass
返回的对象。对应方法为Proxy.getProxyClass
, 那我们查看方法getProxyClass
省略一些代码,我们可以看到是方法ProxyGenerator.generateProxyClass
做了一个代理类的生成,返回值的一个代理文件的字节数组,那么我们可以将这个字节数组输出为文件看看是什么
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
修改测试代码
public class MainTest {
public static void main(String[] args) throws Exception {
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
IPersonService service = new PersonServiceImpl();
byte[] proxyClassBytes = ProxyGenerator.generateProxyClass("$ProxyClass",
service.getClass().getInterfaces(), accessFlags);
FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\EDENJIL\\Desktop\\bb\\$ProxyClass.class"));
fos.write(proxyClassBytes);
fos.flush();
fos.close();
}
}
生成了文件$ProxyClass.class
使用JD-GUI反编译工具查看,我们可以发现java动态代理,使用了字节重组技术,生成了新的代理类$ProxyClass,代理类实现了接口IPersonService
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import priv.dengjili.spring.design.day01.proxy.IPersonService;
public final class $ProxyClass extends Proxy implements IPersonService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $ProxyClass(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void sayHello() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("priv.dengjili.spring.design.day01.proxy.IPersonService").getMethod("sayHello", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
接着我们分析代码
IPersonService proxyService = (IPersonService) proxyClass.getConstructor(InvocationHandler.class).newInstance(h);
proxyService.sayHello();
从代理类$ProxyClass可以看出,我们需要一个类型为InvocationHandler
的入参,同时执行proxyService.sayHello()
方法时,对应代理类执行的也是InvocationHandler
方法逻辑。
public final void sayHello() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
对应我们的实现类
public class InvocationHandlerImpl implements InvocationHandler {
private IPersonService service;
public InvocationHandlerImpl(IPersonService service) {
this.service = service;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==>");
System.out.println("====>");
Object invoke = method.invoke(service, args);
System.out.println("======>");
System.out.println("========>");
return invoke;
}
}
以上即是JDK动态代理思想,核心为字节码重组