在说jdk的动态代理之前,也顺便说下与之对应的静态代理因为比较简单, 就不讲了,直接来动态代理. 1.首先定义一个接口
public interface Man {
void findObject()throws Throwable;
}
2.定义一个实现类,
public class Zhangsan implements Man {
@Override
public void findObject() {
System.out.println("oh , i find you.");
}
}
- 定义InvocationHandler
public class JdkHandler implements InvocationHandler {
private Object target;
JdkHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
method.invoke(target,null);
System.out.println("before");
return null;
}
}
- 简单测试Demo:
public class TestMain {
public static void main(String[] args) throws Throwable{
System.setProperty("dk.proxy.ProxyGenerator.saveGeneratedFiles",true);
Man man = new Zhangsan();
InvocationHandler handler = new JdkHandler(man);
Man man1 = (Man) Proxy.newProxyInstance(TestMain.class.getClassLoader(),new Class[]{Man.class},handler);
man1.findObject();
}
}
执行程序后,可以com.sun.proxy包路径下生成了$Proxy0.class文件,可以看是下面这个样子,可以看出生成这个类是继承Proxy,并实现了接口,由于java单继承的,这也觉得了jdk的动态代理只能实现, 对接口的动态代理类,然后传入的 InvocationHandler的实现类,从而实现对接口代理
final class $Proxy0 extends Proxy implements Man {
private static Method m0;
private static Method m1;
private static Method m2;
private static Method m3;
public $Proxy0(InvocationHandler param1) {
super(var1);
}
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findObject() throws Throwable {
super.h.invoke(this, m3, (Object[])null);
}
static {
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.jdk14.demo.dynamic.myjdk.Man").getMethod("findObject");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
下面看下这个类是如何生成的 通过Proxy类生成代理生成类,首先获取代理类的构造函数,然后通过newProxyInstance生成代理类实例,这个函数比较获取实例比较复杂,下面会详细介绍.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h) {
Objects.requireNonNull(h);
final Class<?> caller = System.getSecurityManager() == null
? null: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
return newProxyInstance(caller, cons, h);
}
获取代理类的构造器,可以看到这里会判断要代理接口的个数,这里看出jdk是支持多个接口和一个接口,下面以一个接口为例,通过ClassLoaderValue<Constructor<?>> proxyCache = new ClassLoaderValue<>(),定义代理的缓 存,将代理接口类作为Sub类的key,然后存在ClassLoader中ConcurrentHashMap这个map缓存.
private static Constructor<?> getProxyConstructor(Class<?> caller,ClassLoader loader, Class<?>... interfaces){
// optimization for single interface
if (interfaces.length == 1) {
Class<?> intf = interfaces[0];
if (caller != null) {
checkProxyAccess(caller, loader, intf);
}
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
} else {
// interfaces cloned
final Class<?>[] intfsArray = interfaces.clone();
if (caller != null) {
checkProxyAccess(caller, loader, intfsArray);
}
final List<Class<?>> intfs = Arrays.asList(intfsArray);
return proxyCache.sub(intfs).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
}
}
代理类是通过ProxyBuilder#build方法创建产生,这里最重要的是defineProxyClass方法返回生产的代理Class,
ProxyBuilder(ClassLoader loader, Class<?> intf){
this(loader, Collections.singletonList(intf));
}
Constructor<?> build() {
Class<?> proxyClass = defineProxyClass(module, interfaces);
final Constructor<?> cons;
try {
cons = proxyClass.getConstructor(constructorParams);
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
return cons;
}
通过Proxy#defineProxyClass方法生成代理的class类, 主要步骤:
- 判断接口的访问属性是否为public的
- 代理类的名称的生成,包名+$Proxy+自增变量,
- 然后获取类加载起,通过ProxyGenerator#generateProxyClass方法生成字节码,(底层使用的ASM生成字节码) 4.通过ClassLoader#defineClass方法将字节码加载JVM 返回对应的CLass 5,标记缓存为true 这里有一个需要留意下ProxyGenerator中有一个标记, jdk.proxy.ProxyGenerator.saveGeneratedFiles的key可以 开启将生成的代理文件保存到文件中,默认路径是com.sun.proxy目录,
private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
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.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL; // non-public, final
String pkg = intf.getPackageName();
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// all proxy interfaces are public
proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
: PROXY_PACKAGE_PREFIX;
} else if (proxyPkg.isEmpty() && m.isNamed()) {
throw new IllegalArgumentException(
"Unnamed package cannot be added to " + m);
}
if (m.isNamed()) {
if (!m.getDescriptor().packages().contains(proxyPkg)) {
throw new InternalError(proxyPkg + " not exist in " + m.getName());
}
}
/*
Choose a name for the proxy class to generate.*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg.isEmpty()
? proxyClassNamePrefix + num
: proxyPkg + "." + proxyClassNamePrefix + num;
ClassLoader loader = getLoader(m);
trace(proxyName, m, loader, interfaces);
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = PROXY_GENERATOR_V49
? ProxyGenerator_v49.generateProxyClass(proxyName, interfaces, accessFlags)
: ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
try {
Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
null, "__dynamic_proxy__");
reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
return pc;
} 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());
}
}
到这里代理类就生成并加载到内存, 就前面贴出来的 $Proxy0类, 这样jdk的生成的代理类的流程就全部清楚了, 可以看到代理类中,通过反射初始获取了Ojbect的hashcode,equals,toString的Method,然后获取接口的Method,缓存到的代理类的属性字段,通过传入InvocationHandler实现, 然后我们就可以,通过Method.invoke反射调用,然后调用前后增加处理逻辑,就可以实现了AOP的功能
最后以一个图总结代理生成的脉络:
总结: 今天主要讲了JDK的动态代理的生成代理咧的流程分析, 其实还有另外一个对于类的代理,这个其实是弥补jdk的 不能实现对于类代理的不足,其实现在jdk实现和cglib实现的底层都是采用了cglib的实现,所以从这一点上看两者性能差不多,其实就cglib而言, 它是既能代理接口 又能代理类,所以cglib才是全面的,但是Spring这些主流框架,如果接口代理还是优先使用jdk的代理,类则是 使用cglib的代理.