HelloInterface ——> sayHello();
Hello implements HelloInterface ——> sayHello() {sout("Hello Eureka");}
public class HelloProxy implements HelloInterface {
private HelloInterface hello = new Hello();
@Override
public sayHello() {
sout("PRE PRE");
hello.sayHello();
sout("POST POST");
}
}
HelloInterface ——> sayHello();
Hello implements HelloInterface ——> sayHello() {sout("Hello Eureka");}
public class HelloProxy implements InvocationHandler {
private Object object;
public HelloProxy (Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("PRE PRE");
method.invoke(object, args);
System.out.println("POST POST");
return null;
}
}
public class ProxyClient {
public static void main(String[] args) {
Hello hello = new Hello();
InvocationHandler handler = new HelloProxy(hello);
// 1
HelloInterface proxy = (HelloInterface) Proxy.newProxyInstance(handler.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
// 2
proxy.sayHello();
}
}
上边的 HelloInterface proxy 这个代理类(代码片段1),其实就是通过动态代理生成的 HelloInterface 接口的实现类,该实现类继承了 Proxy 这个类,核心代码如下(通过反编译生成的,实际代码还是比较多的):
//继承了Proxy类
public final class $Proxy extends Proxy implements HelloInterface {
public $Proxy(InvocationHandler var1) throws {
super(var1);
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
}
代码片段 2 执行会调用这个动态生成的代理实现类的 sayHello 方法。
- JDK 内部需要通过类加载器作为缓存的 key
- 需要类加载器生成 class
生成的代理类继承了 Proxy,由于 java 是单继承,所以只能实现接口,通过接口实现,充分利用了 java 的多态特性,也符合基于接口编码的规范
因为生成的代理类已经继承了 Proxy 类,Java 是单继承的,所以没法再继承另外一个类了。cglib 是通过操作字节码去完成代理的,其实JDK动态代理也操作了字节码。
都要创建代理类,以及代理类都要实现接口等。
- 在静态代理中我们需要对哪个接口和哪个被代理类创建代理类,所以我们在编译前就需要代理类实现与被代理类相同的接口,并且直接在实现的方法中调用被代理类相应的方法。
- 但是动态代理则不同,我们不知道要针对哪个接口、哪个被代理类创建代理类,因为它是在运行时被创建的。
- JDK 静态代理是通过直接编码创建的,JDK 动态代理是利用反射机制在运行时创建代理类的。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
// 如果 h 为空将抛出异常
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);
final InvocationHandler ih = h;
// 假如代理类的构造函数是 private 的,就使用反射来 set accessible
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);
}
}
/**
* 生成一个代理类,但是在调用本方法之前必须进行权限检查
*/
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
// 如果接口数量大于 65535,抛出非法参数错误
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果在缓存中有对应的代理类,那么直接返回。
// 否则代理类将由 ProxyClassFactory 来创建
return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
// 通过上游方法,可以知道 key 是类加载器,这里是通过类加载器可以获得第一层 key
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 我们查看 map 的定义,可以看到 map 变量是一个两层的 ConcurrentMap
// 通过第一层 key 尝试获取数据
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 如果 valuesMap 为空,就新建一个 ConcurrentHashMap,
// key 就是生成出来的 cacheKey,并把这个新建的 ConcurrentHashMap 推到 map
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// 通过上游方法可以知道 key 是类加载器,parameter 是类本身,
// 这里是通过类加载器和类本身获得第二层 key
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// 如果有缓存,直接调用 get 方法后返回,当没有缓存,会继续执行后面的代码,
// 由于 while (true),会第二次跑到这里,再 get 返回出去,
// 其中 get 方法调用的是 WeakCahce 中的静态内部类 Factory 的 get 方法
V value = supplier.get();
if (value != null) {
return value;
}
}
// 当 factory 为空,会创建 Factory 对象
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// 当没有代理类缓存的时候,会运行到这里,把 Factory 的对象赋值给 supplier ,
//进行下一次循环,supplier 就不为空了,可以调用 get 方法返回出去了,
//这个 Factory 位于 WeakCahce 类中,是一个静态内部类
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
/**
* 里面有一个根据给定ClassLoader和Interface来创建代理类的工厂函数
*
*/
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 代理类的名字的前缀统一为“$Proxy”
private static final String proxyClassNamePrefix = "$Proxy";
// 每个代理类前缀后面都会跟着一个唯一的编号,如$Proxy0、$Proxy1、$Proxy2
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) {
/*
* 验证类加载器加载接口得到对象是否与由apply函数参数传入的对象相同
*/
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对象是不是接口
*/
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; // 声明代理类所在的package
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* 记录一个非公共代理接口的包,以便在同一个包中定义代理类。同时验证所有非公共
* 代理接口都在同一个包中
*/
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) {
// 如果全是公共代理接口,那么生成的代理类就在com.sun.proxy package下
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 为代理类生成一个name package name + 前缀+唯一编号
* 如 com.sun.proxy.$Proxy0.class
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成指定代理类的字节码文件
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
private byte[] generateClassFile() {
//下面一系列的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod)
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
//获得接口中所有方法并添加到代理方法中
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}
Iterator var11 = this.proxyMethods.values().iterator();
//验证具有相同方法签名的方法的返回类型是否一致
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}
//后面一系列的步骤用于写代理类Class文件
Iterator var15;
try {
//生成代理类的构造函数
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
//将代理类字段声明为Method,并且字段修饰符为 private static.
//因为 10 是 ACC_PRIVATE和ACC_STATIC的与运算 故代理类的字段都是 private static Method ***
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName,
"Ljava/lang/reflect/Method;", 10));
//生成代理类的方法
this.methods.add(var16.generateMethod());
}
}
//为代理类生成静态代码块对某些字段进行初始化
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
if(this.methods.size() > '\uffff') { //代理类中的方法数量超过65535就抛异常
throw new IllegalArgumentException("method limit exceeded");
} else if(this.fields.size() > '\uffff') {// 代理类中字段数量超过65535也抛异常
throw new IllegalArgumentException("field limit exceeded");
} else {
// 后面是对文件进行处理的过程
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
var1 = this.interfaces;
var2 = var1.length;
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
this.cp.getClass(dotToSlash(var4.getName()));
}
this.cp.setReadOnly();
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);
try {
var14.writeInt(-889275714);
var14.writeShort(0);
var14.writeShort(49);
this.cp.write(var14);
var14.writeShort(this.accessFlags);
var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var14.writeShort(this.interfaces.length);
Class[] var17 = this.interfaces;
int var18 = var17.length;
for(int var19 = 0; var19 < var18; ++var19) {
Class var22 = var17[var19];
var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
}
var14.writeShort(this.fields.size());
var15 = this.fields.iterator();
while(var15.hasNext()) {
ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
var20.write(var14);
}
var14.writeShort(this.methods.size());
var15 = this.methods.iterator();
while(var15.hasNext()) {
ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
var21.write(var14);
}
var14.writeShort(0);
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
private void addProxyMethod(Method var1, Class<?> var2) {
String var3 = var1.getName();//获得方法名称
Class[] var4 = var1.getParameterTypes();//获得方法参数类型
Class var5 = var1.getReturnType();//获得方法返回类型
Class[] var6 = var1.getExceptionTypes();//异常类型
String var7 = var3 + getParameterDescriptors(var4);//获得方法签名
Object var8 = (List)this.proxyMethods.get(var7);//根据方法前面获得proxyMethod的value
if(var8 != null) {//处理多个代理接口中方法重复的情况
Iterator var9 = ((List)var8).iterator();
while(var9.hasNext()) {
ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod)var9.next();
if(var5 == var10.returnType) {
ArrayList var11 = new ArrayList();
collectCompatibleTypes(var6, var10.exceptionTypes, var11);
collectCompatibleTypes(var10.exceptionTypes, var6, var11);
var10.exceptionTypes = new Class[var11.size()];
var10.exceptionTypes = (Class[])var11.toArray(var10.exceptionTypes);
return;
}
}
} else {
var8 = new ArrayList(3);
this.proxyMethods.put(var7, var8);
}
((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2, null));
}
基于 ASM 的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。ASM是一个轻量但高性能的字节码操作框架来转化字节码,产生新类。值得说的是,它比JDK动态代理还要快。
/**
* 被代理类
*/
public class HelloConcrete {
public String sayHello(String str) {
return "HelloConcrete: " + str;
}
}
public class MyMethodInterceptor implements MethodInterceptor {
public static Object getProxy(Class targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MyMethodInterceptor());
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("You said: " + Arrays.toString(args));
return proxy.invokeSuper(obj, args);
}
}
public static void main(String[] args) {
HelloConcrete proxy = (HelloConcrete) MyMethodInterceptor.getProxy(HelloConcrete.class);
System.out.println(proxy.sayHello("I love you!"));
}
上述代码中,我们通过 CGLIB 的 Enhancer 来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用 create() 方法得到代理对象,对这个对象所有非 final 方法的调用都会转发给 MethodInterceptor.intercept()方法,在 intercept() 方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;通过调用 MethodProxy.invokeSuper() 方法,我们将调用转发给原始对象,具体到本例,就是 HelloConcrete 的具体方法。CGLIG 中 MethodInterceptor 的作用跟 JDK 代理中的 InvocationHandler 很类似,都是方法调用的中转站。
- class=class cglib.HelloConcrete$$EnhancerByCGLIB$$e3734e52
- superClass=class lh.HelloConcrete
- interfaces=interface net.sf.cglib.proxy.Factory
- invocationHandler=not java proxy class
CGLIB 代理之后的对象类型是 cglib.HelloConcrete$$EnhancerByCGLIB$$e3734e52,这是 CGLIB 动态生成的类型;父类是 HelloConcrete,印证了 CGLIB 是通过继承实现代理;同时实现了 net.sf.cglib.proxy.Factory 接口,这个接口是 CGLIB 自己加入的,包含一些工具方法。
对于从 Object 中继承的方法,CGLIB 代理也会进行代理,如 hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是 final 方法,CGLIB 无法代理。
既然是继承就不得不考虑 final 的问题。我们知道 final 类型不能有子类,所以 CGLIB 不能代理 final 类型。同样,只能代理非 final 修饰的非抽象类的非 final 方法。
public class HelloConcrete$$EnhancerByCGLIB$$e3734e52 extends HelloConcrete implements Factory {
...
private MethodInterceptor CGLIB$CALLBACK_0; // ~~
...
public final String sayHello(String paramString) {
...
MethodInterceptor tmp17_14 = CGLIB$CALLBACK_0;
if (tmp17_14 != null) {
// 将请求转发给 MethodInterceptor.intercept() 方法
return (String)tmp17_14.intercept(this,
CGLIB$sayHello$0$Method,
new Object[] { paramString },
CGLIB$sayHello$0$Proxy);
}
return super.sayHello(paramString);
}
...
}