- JDK实现动态代理需要实现类通过接口定义业务方法。
- CGLib采用了非常底层的字节码技术,其原理是通过目标类的字节码为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
- 底层使用字节码处理框架ASM,来转换字节码并生成新的类。
- 更详细一点说,代理类将目标类作为自己的父类并为其中的每个非final委托方法创建两个方法:
- 一个是与目标方法签名相同的方法,它在方法中会通过super调用目标方法;
- 另一个是代理类独有的方法,称之为Callback回调方法,它会判断这个方法是否绑定了拦截器(实现了MethodInterceptor接口的对象),若存在则将调用intercept方法对目标方法进行代理,也就是在前后加上一些增强逻辑。intercept中就会调用上面介绍的签名相同的方法。
一、使用CGLib创建代理类
(1)引入CGLib依赖
(1)目标类
public class HelloServiceImpl {
public void say(){
System.out.println("hello everyone");
}
}
(2)生成方法拦截器
(3)生成代理对象
这里Enhancer类是CGLib中的一个字节码增强器,它可以方便的对目标类进行扩展。
- 首先将目标类HelloServiceImpl设置成父类;
- 然后设置拦截器HelloMethodInterceptor;
- 最后执行enhancer.create()动态生成一个代理类,并从Object强制转型成父类型HelloServiceImpl;
- 最后,在代理类上调用方法。
二、对不同方法执行不同的回调逻辑
2.1 JDK动态代理的方式
在JDK动态代理中,通过InvocationHandler
接口方法的调用对代理类内的所以方法都有效。我们往往需要对Method的Name进行判断,然后针对不同的Method编写不同的逻辑,如下:
class MyInvocationHandler implements InvocationHandler {
//具体的调用类
Object target;
public MyInvocationHandler(Object obj) {
target = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当前所持有的proxy对象
//method表示当前别调用的方法
//args表示方法中传递的参数
System.out.println("method name:"+method.getName());
if(method.getName().equals("add")){
if(args[0].equals("apple")){
return false;
}
}
return method.invoke(target, args);
}
}
2.2 CGLib的方式
首先介绍两个概念:
- 回调数组Callback[]:不同的Method的调用可以对应不同的回调函数。在动态代理中,回调函数就是拦截器需要执行的函数,所以我们说回调函数,可以约等于拦截器。拦截器通过实现
MethodInterceptor
接口定义。 - 回调过滤器CallbackFilter:
int accept(Method method)
返回的值为数字代表了Callback数组中的索引位置,即Method对应的Callback。
(1)定义实现过滤器CallbackFilter接口的类:
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
public class TargetMethodCallbackFilter implements CallbackFilter {
/**
* 过滤方法
* 返回的值为数字,代表了Callback数组中的索引位置,要到用的Callback
*/
@Override
public int accept(Method method) {
if(method.getName().equals("method1")){
System.out.println("filter method1 ==0");
return 0;
}
if(method.getName().equals("method2")){
System.out.println("filter method2 ==1");
return 1;
}
if(method.getName().equals("method3")){
System.out.println("filter method3 ==2");
return 2;
}
return 0;
}
}
(2)为代理类设置回调数组和回调过滤器:
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
public class TestCglib {
public static void main(String args[]) {
Enhancer enhancer =new Enhancer();
enhancer.setSuperclass(TargetObject.class);
CallbackFilter callbackFilter = new TargetMethodCallbackFilter();
/**
* (1)callback1:方法拦截器
(2)NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
(3)FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
*/
Callback noopCb=NoOp.INSTANCE;
Callback callback1=new TargetInterceptor();
Callback fixedValue=new TargetResultFixed();
Callback[] cbarray=new Callback[]{callback1,noopCb,fixedValue};
//enhancer.setCallback(new TargetInterceptor());
enhancer.setCallbacks(cbarray);
enhancer.setCallbackFilter(callbackFilter);
TargetObject targetObject2=(TargetObject)enhancer.create();
System.out.println(targetObject2);
System.out.println(targetObject2.method1("mmm1"));
System.out.println(targetObject2.method2(100));
System.out.println(targetObject2.method3(100));
System.out.println(targetObject2.method3(200));
}
}
import net.sf.cglib.proxy.FixedValue;
public class TargetResultFixed implements FixedValue{
/**
* 该类实现FixedValue接口,同时锁定回调值为999
* (整型,CallbackFilter中定义的使用FixedValue型回调的方法为getConcreteMethodFixedValue,该方法返回值为整型)。
*/
@Override
public Object loadObject() throws Exception {
System.out.println("锁定结果");
Object obj = 999;
return obj;
}
}