Cglib代理
上面的靜態(tài)代理和動(dòng)態(tài)代理模式都是要求目標(biāo)對(duì)象是實(shí)現(xiàn)一個(gè)接口的目標(biāo)對(duì)象,但是有時(shí)候目標(biāo)對(duì)象只是一個(gè)單獨(dú)的對(duì)象,并沒(méi)有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候就可以使用以目標(biāo)對(duì)象子類(lèi)的方式類(lèi)實(shí)現(xiàn)代理,這種方法就叫做:Cglib代理
Cglib代理,也叫作子類(lèi)代理,它是在內(nèi)存中構(gòu)建一個(gè)子類(lèi)對(duì)象從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象功能的擴(kuò)展.
- JDK的動(dòng)態(tài)代理有一個(gè)限制,就是使用動(dòng)態(tài)代理的對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口,如果想代理沒(méi)有實(shí)現(xiàn)接口的類(lèi),就可以使用Cglib實(shí)現(xiàn).
- Cglib是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類(lèi)與實(shí)現(xiàn)java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)
- Cglib包的底層是通過(guò)使用一個(gè)小而塊的字節(jié)碼處理框架ASM來(lái)轉(zhuǎn)換字節(jié)碼并生成新的類(lèi).不鼓勵(lì)直接使用ASM,因?yàn)樗竽惚仨殞?duì)JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉.
Cglib子類(lèi)代理實(shí)現(xiàn)方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已經(jīng)包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在內(nèi)存中動(dòng)態(tài)構(gòu)建子類(lèi)
3.代理的類(lèi)不能為final,否則報(bào)錯(cuò)
4.目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法.
代碼示例:
目標(biāo)對(duì)象類(lèi):UserDao.java
/**
* 目標(biāo)對(duì)象,沒(méi)有實(shí)現(xiàn)任何接口
*/
public class UserDao {
public void save() {
System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
}
}
Cglib代理工廠:ProxyFactory.java
/**
* Cglib子類(lèi)代理工廠
* 對(duì)UserDao在內(nèi)存中動(dòng)態(tài)構(gòu)建一個(gè)子類(lèi)對(duì)象
*/
public class ProxyFactory implements MethodInterceptor{
//維護(hù)目標(biāo)對(duì)象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象
public Object getProxyInstance(){
//1.工具類(lèi)
Enhancer en = new Enhancer();
//2.設(shè)置父類(lèi)
en.setSuperclass(target.getClass());
//3.設(shè)置回調(diào)函數(shù)
en.setCallback(this);
//4.創(chuàng)建子類(lèi)(代理對(duì)象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("開(kāi)始事務(wù)...");
//執(zhí)行目標(biāo)對(duì)象的方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事務(wù)...");
return returnValue;
}
}
測(cè)試類(lèi):
/**
* 測(cè)試類(lèi)
*/
public class App {
@Test
public void test(){
//目標(biāo)對(duì)象
UserDao target = new UserDao();
//代理對(duì)象
UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
//執(zhí)行代理對(duì)象的方法
proxy.save();
}
}
在Spring的AOP編程中:
如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,用JDK代理
如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,用Cglib代理