JDK动态代理和Cglib动态代理都是Java中常用的动态代理实现方式,它们各有特点和应用场景:
-
JDK动态代理:JDK动态代理是基于接口的代理方式。它使用
java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口来创建代理对象。在这种方式下,代理类在运行时动态创建,并且必须实现一个或多个接口。使用JDK动态代理时,你需要提供一个实现了InvocationHandler
接口的类,这个类的invoke
方法将定义代理逻辑。实现步骤大致如下:
- 定义一个接口和该接口的实现类;
- 创建一个实现了
InvocationHandler
接口的处理器类; - 使用
Proxy.newProxyInstance
方法动态创建代理对象。
-
Cglib动态代理:与JDK动态代理不同,Cglib代理不需要接口,它是通过继承方式实现的。Cglib包含了一组底层字节码操作工具,能动态生成新的类。它通过继承目标类并重写其中的方法来实现代理。由于是通过继承实现,因此它不能代理声明为final的类和方法。
实现步骤大致如下:
- 创建一个实现了
MethodInterceptor
接口的类; - 使用Cglib的
Enhancer
类来创建代理对象,指定父类和回调。
- 创建一个实现了
在选择使用哪种代理方式时,如果所有目标对象都实现了接口,可以使用JDK动态代理;如果目标对象没有实现接口,或者你需要代理类的所有方法,那么可以考虑使用Cglib代理。
JDK动态代理
如何创建代理对象:使用Proxy类中的newProxyInstance方法
创建代理对象的要求:被代理类至少实现一个接口
newProxyInstance方法的参数
ClassLoader:类加载器,同于加载被代理对象字节码
Class[]:字节码数组---用于让代理对象和被代理对象拥有相同的方法
InvocationHandler:用于提供被增强的代码
/**
接口类
*/
public interface FindHouse2 {
/**
* 找房子
*/
void find1();
/**
* 找房子
*/
void find2();
/**
* 获取名字
* @return
*/
String getName();
}
/**
测试类
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
//如何动态创建一个代理类对象(接口的代理类对象)
//【这里代理的是FindHouse2.class类】
FindHouse2 obj = (FindHouse2) (Proxy.newProxyInstance(
FindHouse2.class.getClassLoader(),
new Class[]{FindHouse2.class},
new MyInvocationHandler()));
//调用代理类对象的find1()方法
obj.find1();
//调用代理类对象的find2()方法
obj.find2();
//调用代理类对象的getName()方法
System.out.println(obj.getName());
}
///方法调用处理器///
private static class MyInvocationHandler implements InvocationHandler {
//钩子函数
//obj.find1() => 调用方法
//在调用方法时,回调这个钩子
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在努力找房源...");
System.out.println("ing...");
System.out.println("找到了xxx的房子");
//返回 null -> 相当于是void
//返回 其他值 -> 相当于是对应的值的类型
return "哈哈";
}
}
}
Cglib动态代理
Enhancer是cglib中使用频率很高的一个类,它是一个字节码增强器,可以用来为无接口的类创建代理。它的功能与java自带的Proxy类挺相似的。它会根据某个给定的类创建子类,并且所有非final的方法都带有回调钩子。最终通过字节码技术动态创建子类实例。
1. 定义类(无需接口):
public class MyCglibClass {
public void doSomething() {
System.out.println("Doing something...");
}
}
2. 创建MethodInterceptor:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method");
return result;
}
}
3. 创建代理实例:
public class Demo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyCglibClass.class);
enhancer.setCallback(new MyMethodInterceptor());
MyCglibClass proxy = (MyCglibClass) enhancer.create();
proxy.doSomething();
}
}