cglib动态代理和retrofit
2019-09-28 本文已影响0人
勇敢地追
1.cglib介绍
代理提供了一个可扩展的机制来控制被代理对象的访问,其实说白了就是在对象访问的时候加了一层封装。jdk动态代理使用起来非常简单,但是有个明显的缺点:需要目标对象实现一个或多个接口。假如你想代理没有接口的类呢?可以使用CGLIB库。
cglib有个最重要的接口MethodInterceptor,这个接口只有一个方法:
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
MethodInterceptor.intercept方法的第一个参数是代理对象,第二个、第三个参数分别是被拦截的方法和方法的参数。
如果想调用被代理对象的原始方法,可以通过使用Method对象来反射调用,或者使用MethodProxy对象。我们通常使用MethodProxy因为它更快。
在intercept方法中,自定义代码可以在原始方法调用前或调用后注入。
2.简单Demo
(记得添加依赖 cglib的github地址有)
- 1.实现一个业务类,注意,这个业务类并没有实现任何接口
public class RetrofitService {
public void loadData(String params) {
System.out.println("RetrofitService loadData " + params);
}
}
- 2.自定义MethodInterceptor
public class RetrofitMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object sub, Method arg1, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
if(arg1.getName().equals("loadData") && objects[0] instanceof String) {
objects[0] = "aaaaaaaaaaa";
}
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
- 3.测试代码
public class Main {
public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "../");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(RetrofitService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new RetrofitMethodInterceptor());
// 创建代理对象
RetrofitService proxy = (RetrofitService) enhancer.create();
// 通过代理对象调用目标方法
proxy.loadData("lalalalalala");
}
}
- 4.查看代理类
加了System.setProperty这句话会在对应的目录下生成对应的包名,里面就会有对应的代理类,里面一共有三个文件,我们暂时只需要这个 RetrofitService$$EnhancerByCGLIB$$158ba096
public final void loadData(final String s) {
MethodInterceptor cglib$CALLBACK_2;
MethodInterceptor cglib$CALLBACK_0;
if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
CGLIB$BIND_CALLBACKS(this);
cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
}
if (cglib$CALLBACK_0 != null) {
cglib$CALLBACK_2.intercept((Object)this, RetrofitService$$EnhancerByCGLIB$$158ba096.CGLIB$loadData$0$Method, new Object[] { s }, RetrofitService$$EnhancerByCGLIB$$158ba096.CGLIB$loadData$0$Proxy);
return;
}
super.loadData(s);
}
可以看到会调用我们自定义的intercept.整个过程其实和jdk动态代理类似