最近在公司看到了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) throws Throwable {
System.out.println("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 userServiceProxy =
(UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
transactionInterceptor);
userServiceProxy.addUser();
}
}
測試結果:
start Transaction
add user
end 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");
methodProxy.invokeSuper(o, args);
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());
UserServiceImpl proxy = (UserServiceImpl)enhancer.create();
proxy.addUser();
}
}
測試結果:
start Transaction by cglib
add user
end Transaction by cglib
結束語
簡單講解了JDK和cglib這2個動態代理,之后會再寫篇文章講講MapperScannerConfigurer的原理實現。