有些Java專案中在mybatis與spring整合中有MapperScannerConfigurer的使用,該類別透過反向代理自動產生基於介面的動態代理類別。
有鑑於此,本文淺析了java的動態代理。
本文使用動態代理模擬處理交易的攔截器。
接口:
public interface UserService { public void addUser(); public void removeUser(); public void searchUser();}實作類別:
public class UserServiceImpl implements UserService { public void addUser() { System.out.println("add user"); } public void removeUser() { System.out.println("remove user"); } public void searchUser() { System.out.println("search user"); }}java動態代理的實作有2種方式
1.jdk自備的動態代理
使用jdk自帶的動態代理需要了解InvocationHandler介面和Proxy類,他們都是在java.lang.reflect套件下。
InvocationHandler介紹:
InvocationHandler是代理實例的呼叫處理程序實作的介面。
每個代理實例都具有一個關聯的InvocationHandler。對代理實例呼叫方法時,這個方法會呼叫InvocationHandler的invoke方法。
Proxy介紹:
Proxy 提供靜態方法用於建立動態代理類別和實例。
實例(模擬AOP處理事務):
public class TransactionInterceptor implements InvocationHandler { private Object target; public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) 行為. ("start Transaction"); method.invoke(target, args); System.out.println("end Transaction"); return null; }}測試程式碼:
public class TestDynamicProxy { @Test public void testJDK() { TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); UserService userService = new UserServiceImpl(); transactionInterceptor.setTarget(userService); UserService userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), transactionInterceptor); userServiceProxy.addUser(); }}測試結果:
start Transactionadd userend Transaction
很明顯,我們透過userServiceProxy這個代理類別進行方法呼叫的時候,會在方法呼叫前後進行交易的開啟和關閉。
2. 第三方庫cglib
CGLIB是一個功能強大的,高效能、高品質的程式碼產生函式庫,用於在運行期擴展Java類別和實作Java介面。
它與JDK的動態代理的之間最大的差異就是:
JDK動態代理是針對介面的,而cglib是針對類別來實現代理的,cglib的原理是對指定的目標類產生一個子類,並覆寫其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類別進行代理。
實例程式碼如下:
public class UserServiceCallBack implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("start Transaction by cglib"); methodxylnin"); ); System.out.println("end Transaction by cglib"); return null; }}測試程式碼:
public class TestDynamicProxy { @Test public void testCGLIB() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(new UserServiceCallBack()); UserService ; proxy.addUser(); }}測試結果:
start Transaction by cglibadd userend Transaction by cglib
有興趣的讀者可以實際測試一下本文實例,相信會有很大的收穫。