動態代理常用的實現方式是發射. 但動態代理不止有反射這一種實現方式.
eg: 動態代理也可以是通過CGLib來實現,而CGLib是基於ASM(一個java字節碼操作框架),而實現的.
簡單說: 動態代理是一種行爲方式,而反射或ASM只是它的一種實現手段而已
JDKPorxy 和CGLib區別:
- JDK Proxy 是java語言自帶的功能,無需加載三方 jar來實現.
- java對 JDK Proxy 提供了穩定的支持,並且會持續提升和更新JDK Proxy, eg: java 8 中JDK Proxy 性能相比於之前版本提升了很多
- JDK Proxy 是通過攔截器加 反射的方式實現的
- JDK Proxy只能代理集成接口的類
- JDK Proxy 實現和調用起來比較簡單
- CGLib 是第三方提供的工具,基於ASM實現的,性能比較高
- CGLib 無需通過接口來實現,它是通過實現子類的方式來完成調用的
public class JDKProxyExample {
static interface Car {
void run();
}
static class Bus implements Car{
@Override
public void run() {
System.out.println("Bus running");
}
}
static class Taxi implements Car{
@Override
public void run() {
System.out.println("Taxi running");
}
}
// 實現 InvocationHandler 接口
static class JDKProxy implements InvocationHandler {
// 代理對象
private Object target;
// 獲取代理對象實例
public Object getInstance(Object target) {
this.target = target;
// 獲得代理的對象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),JDKProxy.this);
}
/**
* 執行代理方法
* @param proxy 代理對象
* @param method 代理方法
* @param args 方法參數
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("動態代理之前的業務處理");
Object invoke = method.invoke(target, args);
return invoke;
}
}
public static void main(String[] args) {
JDKProxy jdkProxy = new JDKProxy();
Car instance = (Car) jdkProxy.getInstance(new Taxi());
instance.run();
Car instance2 = (Car)jdkProxy.getInstance(new Bus());
instance2.run();
}
}
依賴:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author xulihui
* @date 2020/4/7 13:10
*/
public class CGLibExample {
static class Car {
public void run() {
System.out.println("Car running");
}
}
static class CGLibProxy implements MethodInterceptor {
// 接收代理對象
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
// 設置父類爲示例
enhancer.setSuperclass(this.target.getClass());
// 回調方法
enhancer.setCallback(this);
// 創建並返回代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法調用前業務處理");
// 執行調用方法
Object invoke = methodProxy.invoke(o, objects);
return invoke;
}
}
public static void main(String[] args) {
// 創建CGLib代理類
CGLibProxy cgLibProxy = new CGLibProxy();
// 初始化代理對象
Car instance = (Car)cgLibProxy.getInstance(new Car());
// 執行方法
instance.run();
}
}
spring框架中同時使用了兩種動態代理 JDK Proxy 和CGLib,
當bean實現了接口時,Spring 就會使用CGLib
沒有實現接口的時候,就會使用CGLib, 也可以在配置中強制使用CGLib, 只需要在Spring 配置中添加 <aop:aspectj-autoproxy proxy-target-class="true"/> 即可。