JDK动态代理的使用与源码分析
JDK动态代理的使用
JDK动态代理的实现是在运行时,根据一组接口定义,使用Proxy、InvocationHandler等工具类去生成一个代理类和代理类实例。
使用
编写一个类实现InvocationHandler接口。
package com.morris.spring.proxy.dynamic.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserServiceInvocationHandler implements InvocationHandler {
private Object tartget;
public UserServiceInvocationHandler(Object tartget) {
this.tartget = tartget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke before");
Object result = method.invoke(tartget, args);
System.out.println("invoke after");
return result;
}
}
测试类
package com.morris.spring.proxy.dynamic.jdk;
import com.morris.spring.service.UserService;
import com.morris.spring.service.UserServiceImpl;
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
public static void main(String[] args) {
UserService userService = (UserService) Proxy.newProxyInstance(JdkProxyDemo.class.getClassLoader(), new Class<?>[]{ UserService.class}, new UserServiceInvocationHandler(new UserServiceImpl()));
userService.query();
}
}
总结:
- 要使用JDK动态代理,目标对象需要实现一个接口。
- JDK动态代理为什么要使用实现接口呢,为什么不像cglib使用继承呢?因为jdk动态代理生成的动态代理类会继承Proxy类,而java是单继承,无法再继承目标类。
- 自定义的InvocationHandler要接收一个目标接口的实现类,因为在代理类中要执行目标对象的方法,所以必须传入目标对象,否则无法执行。
代理类长什么样?
使用arthas工具将内存中的com.sun.proxy包下的class文件dump下来,反编译后内容如下,内容已去除toString等不重要方法和属性。
package com.sun.proxy;
import com.morris.spring.proxy.IUserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements IUserService {
private static Method m3;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
static {
try {
m3 = Class.forName("com.morris.spring.proxy.IUserService").getMethod("query", new Class[0]);
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
public final String query() {
try {
return (String) this.h.invoke(this, m3, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
}
从jdk动态代理生成的代理类的内容可以发现:
- 代理类默认的包名为com.sun.proxy,后面看源码会发现这个会根据目标接口的访问修饰符来决定(如果是public,包名为com.sun.proxy,如果是protected,包名会跟目标接口包名相同,接口的访问修饰符不能为private)。
- 代理类名为$Proxy开头,后面的数字每生成一个代理类会自增。
- 代理类继承了Proxy类,实现了目标接口。
- 代理类的目标方法会调用自己实现的InvocationHandler接口的invoke方法。
JDK动态代理源码解读
JDK动态代理的源码的入口为Proxy.newProxyInstance
Proxy的数据结构
private static final Class<?>[] constructorParams = { InvocationHandler.class }; // Proxy的构造方法的参数类型
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); // 代理类的缓存
protected InvocationHandler h; // 存放传入的自定义的InvocationHandler,供其子类$Proxy0调用
Proxy.newProxyInstance
java.lang.reflect.Proxy#newProxyInstance
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);
}
// 获得构造参数是InvocationHandler的构造方法
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;
}
});
}
// 调用构造方法$Proxy0(InvocationHandler h)生成代理对象实例
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()的代码如下
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
// 从静态属性proxyClassCache中获取,不存在则会调用ProxyClassFactory生成
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory
ProxyClassFactory是一个BiFunction,用于生成代理类
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy"; // 生成的代理类的名称前缀
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong(); // 计数器
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/* * Verify that the class loader resolves the name of this * interface to the same Class object. */
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
// 判断传入的接口是不是传入的classloader加载的
// 对象的比较在同一个classloader下才有意义
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/* * Verify that the Class object actually represents an * interface. */
// 传入的是不是一个接口,只能代理接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/* * Verify that this interface is not a duplicate. */
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */
// 判断接口的访问修饰符,public的接口,生成的类的包名可以随意,但是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) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/* * Choose a name for the proxy class to generate. */
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/* * Generate the specified proxy class. */
// 生成代理类.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());
}
}
}
从源码可以看出:
- jdk动态代理生成的代理类继承了Proxy类。
- 底层是直接生成.class字节码数组,内存操作,速度快。
- 底层使用了WeakCache做缓存。
还没有评论,来说两句吧...