目标
理解spring
中如何通过cglib
的方式生成动态代理。 我们都知道,spring
中存在两种动态代理的方式,第一个是jdk
动态代理的方式,本质是通过反射实现,第二个是cglib
的方式,这个是需要操作字节码实现。第一种方式虽然效率会更高,但是却存在硬伤,代理类必须是基于接口的。而方式二则没有这些限制。我们之前有一篇文章是分析jdk动态代理方式实现,这篇文章则重点是cglib
方式如何实现动态代理。
本文将会通过将运行期间的对象保存到本地,生成java
的字节码,窥探cglib
的运行机制。
源码分析
入口类,从这里创建cglib对象
public class testAopCglibKProxy {
public static void main(String[] args) {
new testAopCglibKProxy().testCglibProxy();
}
public void testCglibProxy() {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/apple/logs");
System.out.println("before Proxy......");
//目标对象(原始对象)
UserServiceImpl userService = new UserServiceImpl();
userService.saveUser("zby", "1234567890");
System.out.println("引入Cglib Proxy代理库 后......");
//代理对象,也就是被增强后的对象 下面这句代码是重点。
UserServiceImpl proxyUserService = (UserServiceImpl) CglibProxyGenerator.generatorCglibProxy(userService, new CustomAspect());
proxyUserService.saveUser("zby", "1234567890");
}
}
cglib的生成器
public class CglibProxyGenerator {
/**
* @param target 需要被代理的委托类对象,Cglib需要继承该类生成子类
* @param aspect 切面对象,改对象方法将在切点方法之前或之后执行
* @return
*/
public static Object generatorCglibProxy(final Object target, final IAspect aspect) {
//3.1 new Enhancer 创建生成器
Enhancer enhancer = new Enhancer();
//3.2 设置需要代理的父类
enhancer.setSuperclass(target.getClass());
//3.3 设置回调 ,具体这个回调是怎么执行,有什么用,我们后文分析
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 执行切面方法
aspect.startTransaction();
// 具体逻辑代码执行,返回值为方法执行结果
Object result = methodProxy.invokeSuper(proxy, args);
// 执行切面方法
aspect.endTrasaction();
// 返回方法执行结果
return result;
}
});
// 3.4 创建代理对象
return enhancer.create();
}
}
下面贴出目标对象&切面对象代码
// 切面对象,也就是需要给目标对象进行增强的一些逻辑内容,比如事物控制等
public class CustomAspect implements IAspect {
@Override
public void startTransaction() {
System.out.println("cglib. I get datasource here and start transaction");
}
public void endTrasaction() {
System.out.println("cglib I get datasource here and end transaction");
}
}
//原始对象,也就是目标对象。没有增强之前的对象
public class UserServiceImpl {
public void saveUser(String username, String password) {
System.out.println("cglib save user[username=" + username + ",password=" + password + "]");
}
}
现在我们展示运行起来后生成的代理对象,虽然只能拿到class文件,但是编辑器可以帮助我们反编译为java代码。
最后就是代码对象反编译的java代码了。
// extends UserServiceImpl 重点 代理对象继承了目标对象
public class UserServiceImpl$$EnhancerByCGLIB$$b4be90dd extends UserServiceImpl 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$saveUser$0$Method;
private static final MethodProxy CGLIB$saveUser$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("org.dromara.hmily.demo.springcloud.order.test.UserServiceImpl$$EnhancerByCGLIB$$b4be90dd");
Class var1;
//目标对象UserServiceImpl 中定义的方法
CGLIB$saveUser$0$Method = ReflectUtils.findMethods(new String[]{"saveUser", "(Ljava/lang/String;Ljava/lang/String;)V"}, (var1 = Class.forName("org.dromara.hmily.demo.springcloud.order.test.UserServiceImpl")).getDeclaredMethods())[0];
//目标对象UserServiceImpl 中定义的方法
CGLIB$saveUser$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;Ljava/lang/String;)V", "saveUser", "CGLIB$saveUser$0");
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");
}
final void CGLIB$saveUser$0(String var1, String var2) {
super.saveUser(var1, var2);
}
//这里重写了父类的方法
public final void saveUser(String var1, String var2) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//前面我们构造Enhance对象的时候往里面填充了MethodInterceptor对象。这个MethodInterceptor就在这个时候会被调用
var10000.intercept(this, CGLIB$saveUser$0$Method, new Object[]{var1, var2}, CGLIB$saveUser$0$Proxy);
} else {
super.saveUser(var1, var2);
}
}
//。。省略
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -630724063:
if (var10000.equals("saveUser(Ljava/lang/String;Ljava/lang/String;)V")) {
return CGLIB$saveUser$0$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
UserServiceImpl$$EnhancerByCGLIB$$b4be90dd var1 = (UserServiceImpl$$EnhancerByCGLIB$$b4be90dd)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
static {
CGLIB$STATICHOOK1();
}
}
小结
从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,
intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中
的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。
至此大致明白了cglib的一个流程。以及实现过程的一些关键因素,但是内部的一些细节仍旧是迷惑的,比如字节码如何生成,等。