浅谈CGLIB动态代理和JDK动态代理 学习笔记
前言
前几天,写一个
case
,做单元的测试。抛出了依赖注入失败的异常,然后发现是没有配置CGLIB
动态代理的原因,默认的JDK
动态代理只能基于接口去代理,被代理的类必须要实现一个接口。而CGLIB
动态代理可以基于类。
JDK动态代理实现AOP
- 定义统一的接口类
IUserService
。
public interface IUserService {
void login();
}
- 定义
UserService
去实现这个接口,加入自己的逻辑。
public class UserService implements IUserService {
@Override
public void login() {
System.out.println("login success");
}
}
- 定义动态代理类
UserDynamicProxy
去实现InvocationHandler
接口。invoke()
方法中可以加入自定义的切面逻辑。被代理的类中方法的执行是由method.invoke(target, args)
完成的。
public class UserDynamicProxy implements InvocationHandler {
private Object target;
public UserDynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("login before");
Object result = method.invoke(target, args);
System.out.println("login after");
return result;
}
}
- 接下来我们写一下测试类,运行一下程序。
public class DymaticProxyDemo {
public static void main(String[] args) {
IUserService userService = new UserService();
UserDynamicProxy handler = new UserDynamicProxy(userService);
IUserService serviceProxy = (IUserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), handler);
serviceProxy.login();
}
}
image.png
-
Proxy.newProxyInstance()
方法可以返回一个指定接口的代理类的实例。我们可以到Proxy
类源码是这样讲到。
> /**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
Proxy.newProxyInstance()
返回的的是一个指定接口的代理类的实例,其调用方法可以调用到指定的调用程序。也就是说serviceProxy.login()
这个方法,其实是调用到UserDynamicProxy
实例中的invoke()方法。
newProxyInstance()
方法中,第一个参数是加载类加载器去定义代理类,第二个参数是接口代理类的接口列表,第三个参数是InvocationHandler
接口的实现类实例去调用处理程序来进行相关的
处理。
CGLIB动态代理实现AOP
- 定义一个
Dog
类,CGLIB
动态代理不需要去定义目标类的同一接口。
public class Dog {
public void call() {
System.out.println("wang wang wang");
}
}
- 定义
CglibProxy
类,它需要去实现MethodInterceptor
这个接口。我们可以在intercept()
方法中,去加入自己的切面逻辑。目标类方法的调用是proxy.invokeSuper(object, args)
触发的。
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
proxy.invokeSuper(object, args);
System.out.println("after");
return null;
}
}
- 接下来我们定义一个工厂类,去获得代理类的实例。
public class Factory {
public static Dog getInstance(CglibProxy proxy) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dog.class);
enhancer.setCallback(proxy);
Dog rayDog = (Dog) enhancer.create();
return rayDog;
}
}
首先去获取Enhancer
类的实例,调用enhancer.setSuperclass()
设置目标类class
对象。观看setSuperClass()
,会去判断这个class
对象是否为空,或者是否为接口,是否为Object
的class
对象。
public void setSuperclass(Class superclass) {
if(superclass != null && superclass.isInterface()) {
this.setInterfaces(new Class[]{superclass});
} else if(superclass != null && superclass.equals(Object.class)) {
this.superclass = null;
} else {
this.superclass = superclass;
}
}
enhancer.setCallback()
这个方法,我们需要传入CglibProxy
的实例作为回调的对象,并且把它放入到一个Callback
类型的数组里面。然后去判断这个数组是否合法。
public void setCallback(Callback callback) {
this.setCallbacks(new Callback[]{callback});
}
public void setCallbacks(Callback[] callbacks) {
if(callbacks != null && callbacks.length == 0) {
throw new IllegalArgumentException("Array cannot be empty");
} else {
this.callbacks = callbacks;
}
}
最后一步enhancer.create()
返回的是一个增强的目标类的实例,此时的rayDog
对象已经不是以前那个Dog
类的, 而是一个增强后的Dog
类的实例了。dog
究极进化成了镭射狗(X-ray Dog
的歌很好听哟,有一首叫Panorama
)。我们可以看到create()
方法是这样实现的。
public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}
private Object createHelper() {
this.preValidate();
Object key = KEY_FACTORY.newInstance(this.superclass != null?this.superclass.getName():null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO?null:new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
private void preValidate() {
if(this.callbackTypes == null) {
this.callbackTypes = CallbackInfo.determineTypes(this.callbacks, false);
this.validateCallbackTypes = true;
}
if(this.filter == null) {
if(this.callbackTypes.length > 1) {
throw new IllegalStateException("Multiple callback types possible but no filter specified");
}
this.filter = ALL_ZERO;
}
}
create()
方法里面调用了createHelper()
,createHelper()
里面又去调用了preValidate()
。
我们进行DEBUG
调试的时候,可以进行完preValidate()
这个方法后,会发现this.callbackTypes
就是MethodInterceptor
类型的TYPE
。
this.callbackTypes = CallbackInfo.determineTypes(this.callbacks, false)
会去解析传入的Callback
数组的类型,并且把他们放入到一个Type
类型的数组里。相关必要的操作做完,就传入Enhancer.EnhancerKey
的实例,调用create(Object key)
去生成增强后的目标类实例。
- 最后编写测试类,启动程序。
public class CglibDemo {
public static void main(String[] args) {
Dog rayDog = Factory.getInstance(new CglibProxy());
rayDog.call();
}
}
image.png
尾言
勿以善小而不为