Java動態代理技術廣泛的應用于我們的項目之中,比如Spring AOP、分布式服務框架等。其主要實現方式有2種,一種是JDK動態代理,一種是cglib動態代理,兩種方式各有優劣,本文在此做一個總結。
JDK動態代理
JDK自帶的代理機制
實現原理:接口,反射。
運行時根據目標類動態創建代理類,代理類和目標類實現相同的接口。調用方調用代理類,代理類反射調用目標類。
JDK動態代理
優點:
- 創建代理性能比cglib好
- JDK自帶,無需引用第三方包
缺點:
- 需要依賴共同的接口,如果目標類沒有實現接口,就無法代理。
- 代理類執行速度較慢
創建代理流程
- 實現InvocationHandler接口,創建自己調用處理器,主要是實現invoke方法。invoke方法負責正真調用目標類的方法。
- 通Proxy.newProxyInstance()創建代理類,需要三個參數:目標類的ClassLoader、Interfaces和InvocationHandler。
實例
package com.javastudy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author fangyi.xfy 2016/8/23 11:29.
*/
public class ProxyFactory implements InvocationHandler {
/**
* 目標對象
*/
private Object target;
/**
* 創建代理類
**/
public Object newProxyInstance(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* 重寫調用方法,此處可以織入代碼,比如AOP切面
**/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before invoke");
Object res = method.invoke(target, args);
System.out.println("after invoke");
return res;
}
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory();
UserService proxy = (UserService) proxyFactory.newProxyInstance(userService);
proxy.addUser("Andy");
}
}
cglib動態代理
cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access. https://github.com/cglib/cglib/wiki
實現原理:繼承,反射。
運行時根據目標類動態創建代理類,代理類是目標類的子類。
優點:
- 執行性能優于JDK動態代理
cglib動態代理
缺點:
- 由于是繼承,無法對final修飾的class代理
- 創建代理類性能較差
創建代理流程
- 實現MethodInterceptor接口,創建自己的方法攔截器,實現intercept方法。
- 通過Enhancer創建目標類的代理,需要目標類的class,MethodInterceptor。
實例
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//設置需要創建子類的類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通過字節碼技術動態創建子類實例
return enhancer.create();
}
//實現MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通過代理類調用父類中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}