功能概述
- Java的动态代理,是代理模式的具体实现,即为其他对象提供一个代理以控制对某个对象的访问。Java的动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler,内部使用了缓存机制和反射机制实现。
功能实践
场景1:为Map接口生成代理
用例代码
@Test
public void test_jdk_dynamic_proxy_v1() {
Map mapProxyInstance = (Map) Proxy.newProxyInstance(
ProxyTest.class.getClassLoader(), new Class[] { Map.class },
new MyInvocationHandler(new HashMap<>()));
mapProxyInstance.put("hello", "world");
mapProxyInstance.get("hello");
CharSequence csProxyInstance = (CharSequence) Proxy.newProxyInstance(
ProxyTest.class.getClassLoader(),
new Class[] { CharSequence.class },
new MyInvocationHandler("Hello World"));
csProxyInstance.charAt(0);
csProxyInstance.length();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
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 {
Object result = method.invoke(target, args);
System.out.println("执行方法:" + method.getName() + ",结果值:" + result);
return result;
}
}
运行结果
执行方法:put,结果值:null
执行方法:get,结果值:world
执行方法:charAt,结果值:H
执行方法:length,结果值:11
结果分析
- 为Map接口创建代理对象。并自定义调用处理器MyInvocationHandler,在使用代理接口调用方法时,就会回调MyInvocationHandler的invoke方法,传入代理对象、调用的方法、参数列表等
场景2:为自定义接口生成代理
用例代码
public void test_jdk_dynamic_proxy_v2() throws IOException {
IHelloProxy helloProxy = (IHelloProxy) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),
new Class[]{IHelloProxy.class}, new MyInvocationHandler(new HelloProxyImpl()));
helloProxy.setProxyName("hello");
String proxyName = helloProxy.getProxyName("hello");
System.out.println("结果值:" + proxyName);
}
public interface IHelloProxy {
String getProxyName(String name);
void setProxyName(String name);
}
public class HelloProxyImpl implements IHelloProxy {
private String proxyName;
private static final String PREFIX = "proxy_";
@Override
public String getProxyName(String name) {
return proxyName;
}
@Override
public void setProxyName(String name) {
proxyName = PREFIX + name;
}
}
- 注明:该场景用到的MyInvocationHandler,在场景1中有声明。
运行结果
执行方法:setProxyName,结果值:null
执行方法:getProxyName,结果值:proxy_hello
结果值:proxy_hello
结果分析
- 在创建代理对象时,指定代理的接口IHelloProxy,以及调用处理器MyInvocationHandler,调用处理器指定了接口实现类,即目标对象
- 在调用接口方法时,即调用调用代理对象的方法,会回调InvocationHandler中的invoke方法,可在该方法中做增强处理
原理分析
Proxy#newProxyInstance创建代理对象分析】
public class Proxy implements java.io.Serializable {
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
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);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e)
}
}
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
}
- 代码解析:
- 代码1)处:WeakCache用来存储代理类的缓存,若无缓存,会通过ProxyClassFactory创建
- 代码2)处:从缓存中查找代理类,若没有创建代理类
- 代码3)处:找到代理类包含InvocationHandler为参数的构造器Constructor,通过反射机制创建代理对象
- 代码4)处:从缓存中去查代理类
ProxyClassFactory#apply创建代理类分析
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
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");
}
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());
}
}
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
- 代码分析:
- 代码1)处:判断如是否能够通过当前加载器加载Class
- 代码2)处:判断代理的是否是接口,不是接口不能代理
- 代码3)处:产生代理类Class的字节数组
- 代码4)处:将字节数组通过native方法得到代理类的Class
功能总结
- CGLIB与JDK动态代理区别
- a)JDK代理只能对实现接口的类生成代理;CGLib是针对类实现代理
- b)JDK代理使用的是反射机制实现aop的动态代理,CGLib代理使用字节码处理框架ASM
- c)JDK动态代理机制是委托机制,CGLib则使用的继承机制