java實(shí)現(xiàn)動(dòng)態(tài)代理方法淺析
一些Java項(xiàng)目中在mybatis與spring整合中有MapperScannerConfigurer的使用,該類通過反向代理自動(dòng)生成基于接口的動(dòng)態(tài)代理類。
有鑒于此,本文淺析了java的動(dòng)態(tài)代理。
本文使用動(dòng)態(tài)代理模擬處理事務(wù)的攔截器。
接口:
public interface UserService {
public void addUser();
public void removeUser();
public void searchUser();
}
實(shí)現(xiàn)類:
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動(dòng)態(tài)代理的實(shí)現(xiàn)有2種方式
1.jdk自帶的動(dòng)態(tài)代理
使用jdk自帶的動(dòng)態(tài)代理需要了解InvocationHandler接口和Proxy類,他們都是在java.lang.reflect包下。
InvocationHandler介紹:
InvocationHandler是代理實(shí)例的調(diào)用處理程序?qū)崿F(xiàn)的接口。
每個(gè)代理實(shí)例都具有一個(gè)關(guān)聯(lián)的InvocationHandler。對代理實(shí)例調(diào)用方法時(shí),這個(gè)方法會(huì)調(diào)用InvocationHandler的invoke方法。
Proxy介紹:
Proxy 提供靜態(tài)方法用于創(chuàng)建動(dòng)態(tài)代理類和實(shí)例。
實(shí)例(模擬AOP處理事務(wù)):
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();
}
}
測試結(jié)果:
start Transaction add user end Transaction
很明顯,我們通過userServiceProxy這個(gè)代理類進(jìn)行方法調(diào)用的時(shí)候,會(huì)在方法調(diào)用前后進(jìn)行事務(wù)的開啟和關(guān)閉。
2. 第三方庫cglib
CGLIB是一個(gè)功能強(qiáng)大的,高性能、高質(zhì)量的代碼生成庫,用于在運(yùn)行期擴(kuò)展Java類和實(shí)現(xiàn)Java接口。
它與JDK的動(dòng)態(tài)代理的之間最大的區(qū)別就是:
JDK動(dòng)態(tài)代理是針對接口的,而cglib是針對類來實(shí)現(xiàn)代理的,cglib的原理是對指定的目標(biāo)類生成一個(gè)子類,并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對final修飾的類進(jìn)行代理。
實(shí)例代碼如下:
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();
}
}
測試結(jié)果:
start Transaction by cglib add user end Transaction by cglib
感興趣的讀者可以實(shí)際測試一下本文實(shí)例,相信會(huì)有很大的收獲。
相關(guān)文章
基于Java注解(Annotation)的自定義注解入門介紹
要深入學(xué)習(xí)注解,我們就必須能定義自己的注解,并使用注解,在定義自己的注解之前,我們就必須要了解Java為我們提供的元注解和相關(guān)定義注解的語法2013-04-04
Mybatis-plus自動(dòng)填充不生效或自動(dòng)填充數(shù)據(jù)為null原因及解決方案
本文主要介紹了Mybatis-plus自動(dòng)填充不生效或自動(dòng)填充數(shù)據(jù)為null原因及解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
jxls2.4.5如何動(dòng)態(tài)導(dǎo)出excel表頭與數(shù)據(jù)
這篇文章主要介紹了jxls2.4.5如何動(dòng)態(tài)導(dǎo)出excel表頭與數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Java concurrency之AtomicReference原子類_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
AtomicReference是作用是對"對象"進(jìn)行原子操作。這篇文章主要介紹了Java concurrency之AtomicReference原子類,需要的朋友可以參考下2017-06-06
Java代碼實(shí)現(xiàn)隨機(jī)生成漢字的方法
今天小編就為大家分享一篇關(guān)于Java代碼實(shí)現(xiàn)隨機(jī)生成漢字的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
java多線程之Future和FutureTask使用實(shí)例
這篇文章主要介紹了java多線程之Future和FutureTask使用實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

