标签:Java 代理 private final static CGLIB 设计模式 Method
和JDK
代理一样,CGLib
代理也是一种动态代理方式,而且相比JDK
代理更加的灵活,可以代理任何类(除了final
修饰的)。
先上代码,还是以买房为例,看下具体实现:
需要被代理的类,这次不是某个接口的实现类,而是一个普通类
public class HouseBuyer {
public void buy() {
System.out.println("要买房");
}
}
代理类
public class CglibHouseCompanyProxy implements MethodInterceptor {
public Object getInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o, objects);
after();
return obj;
}
private void before() {
System.out.println("before method ...");
}
private void after() {
System.out.println("after method ...");
}
}
在被客户端实际调用的时候
HouseBuyer buyer = (HouseBuyer) new CglibHouseCompanyProxy().getInstance(new HouseBuyer());
buyer.buy();
是不是似曾相识,代理类都是实现了某个接口,然后重写一个方法,看着都是利用反射去获取被代理类的方法,经过增强处理然后去执行。
同样的,经过断点调试后会发现,真正执行方法的对象也是也是新的对象,
可以通过org.springframework.cglib.core
包里的DebuggingClassWriter
类将代理过程的字节码文件生成到磁盘上来简单分析下,在上面调用方法的前面加上
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "external-file/cglib-debug");
重新跑一遍代码,在项目根目录下会生成external-file
文件夹,在里面找到HouseBuyer$$EnhancerByCGLIB$$a1e313be
类进行反编译,节选部分代码
public class HouseBuyer$$EnhancerByCGLIB$$a1e313be extends HouseBuyer implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$buy$0$Method;
private static final MethodProxy CGLIB$buy$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("xxx.xxx.xxx.cglibproxy.HouseBuyer$$EnhancerByCGLIB$$a1e313be");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$buy$0$Method = ReflectUtils.findMethods(new String[]{"buy", "()V"}, (var1 = Class.forName("xxx.xxx.xxx.cglibproxy.HouseBuyer")).getDeclaredMethods())[0];
CGLIB$buy$0$Proxy = MethodProxy.create(var1, var0, "()V", "buy", "CGLIB$buy$0");
}
final void CGLIB$buy$0() {
super.buy();
}
public final void buy() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$buy$0$Method, CGLIB$emptyArgs, CGLIB$buy$0$Proxy);
} else {
super.buy();
}
}
}
代理生成的类继承了被代理类,并且里面还有一个被final
修饰的buy
方法,这个方法里MethodInterceptor
获取引用之后就会执行intercept
方法,而我们的代理类也是MethodInterceptor
接口的实现类,所以在客户端类时间执行的时候最终执行的是代理类的intercept
方法。至于CGLib
是如何生成这个代理对象的,可以从代理类获取增强实例enhancer.create()
那里一步一步分析,这里就不做了。
小结
CGLib
通过为代理类生成一个继承的子类形式来代理,对被代理类没有限制,不需要像JDK
代理那样需要实现接口。底层通过字节码处理框架ASM
来生成Java
的字节码形成新的类,也就是上文新的代理类。简而言之:
JDK
代理是实现了被代理对象的接口,而CGLib
代理是继承了被代理对象- 两者都是在运行期间生成字节码,
JDK
代理是直接写Class
字节码,而CGLib
是通过ASM
框架来写Class
字节码
标签:Java,代理,private,final,static,CGLIB,设计模式,Method 来源: https://blog.csdn.net/liu_1024_/article/details/113307196
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。