?? 作者:江南白衣?

?? 反射、Proxy和元數(shù)據(jù)是Java最強的三個特征,再加上CGLib (Code Generation Library)和ASM,使得Java雖然沒有Ruby,Python般后生可畏,一樣能做出強悍的框架。
???Proxy可以看作是微型的AOP,明白提供了在繼承和委托之外的第三個代碼封裝途徑,只要有足夠的想象力,可以做得非常好玩,Spring的源碼里用Proxy就用得很隨便,看得我非常眼紅。可惜Proxy必須基于接口。因此Spring的做法,基于接口的用proxy,否則就用cglib。AOP么,一般小事非compoent一級的就不麻煩AspectJ出手了。

????cglib的Enhancer說起來神奇,用起來一頁紙不到就講完了。
??? 它的原理就是用Enhancer生成一個原有類的子類,并且設置好callback到proxy, 則原有類的每個方法調(diào)用都會轉(zhuǎn)為調(diào)用實現(xiàn)了MethodInterceptor接口的proxy的intercept()?函數(shù):
public?Object?intercept(Object?o,Method?method,Object[]?args,MethodProxy?proxy)

?在intercept()函數(shù)里,你可以在執(zhí)行Object result=proxy.invokeSuper(o,args);來執(zhí)行原有函數(shù),在執(zhí)行前后加入自己的東西,改變它的參數(shù)值,也可以瞞天過海,完全干別的。說白了,就是AOP中的around advice。

??? AOP沒有出現(xiàn)以前,該領域經(jīng)典的設計模式是Decorator,像Java IO Stream的設計就是如此.不過,如果為每個DAO, 每個方法的寫Decorator函數(shù)會寫死人的,所以用上cglib的好處是一次過攔截所有方法。?

???? 另外,cglib除了Enhancer之外,還有BulkBean和Transform,都是Hibernate持久化的基礎,但文檔貧乏,一時還沒去看怎么用。

1.AOP里講了一百遍阿一百遍的log aspect在cglib是這樣做的:


???
public?class?LogDAOProxy?implements?MethodInterceptor
???{
???????
private?Logger?log=Logger.getLogger(LogDAOProxy.class);
???????
private?Enhancer?enhancer=new?Enhancer();
????????
//返回DAO的子類
???????public?Object?getDAO(Class?clz)
???????{
???????????enhancer.setSuperclass(clz);
???????????enhancer.setCallback(
this);
???????????
return?enhancer.create();
???????}
???????
//默認的攔截方法
??????public?Object?intercept(Object?o,Method?method,Object[]?args,MethodProxy?proxy)?throws?Throwable
??????{
???????????log.info(
"調(diào)用日志方法"+method.getName());
???????????Object?result
=proxy.invokeSuper(o,args);
???????????
return?result;
??????}
???}

??? 應用的代碼:
????LogDAOProxy?proxy?=?new?LogDAOProxy();
????GoodsDAO??dao?
=?(GoodsDAO)proxy.getDAO(GoodsDAO.class);
????dao.insert(goods);

2.而在Spring的管理下應該略加修改的高級Decorator
?? 上面的例子用return?enhancer.create();創(chuàng)建子類實例,但在Spring管理下,一些Bean的實例必須由Spring來創(chuàng)建和管理,而不由enhancer來創(chuàng)建的。所以我對上述用法略加修改,使它真正當一個Proxy的角色,請對比黑體字的部分


??public?class?LogDAOProxy?implements?MethodInterceptor
??{
???????
private?Logger?log=Logger.getLogger(LogDAOProxy.class);
???????
private?Object?dao=null;
???????
private?Enhancer?enhancer=new?Enhancer();
????????
//返回DAO的子類
???????public?Object?getDAO(Class?clz,Object?dao)
???????{
???????????
this.dao?=?dao;
???????????enhancer.setSuperclass(clz);
???????????enhancer.setCallback(
this);
???????????
return?enhancer.create();
???????}??????
???????
//默認的攔截方法
??????public?Object?intercept(Object?o,Method?method,Object[]?args,MethodProxy?proxy)?throws?Throwable
??????{
???????????log.info(
"調(diào)用日志方法"+method.getName());
???????????Object?result
=proxy.invoke(dao,?args);
???????????
return?result;
??????}
??}

可見,原來模式里在getDao()時由enhancer創(chuàng)建dao,而?調(diào)用intercept時則將enhancer創(chuàng)建的dao以Object o參數(shù)傳回。
而新模式里,dao在getDao()時從外面?zhèn)魅耄琫nhancer.create()返回的是一個proxy. 而調(diào)用intercept時,實際會用之前傳入的dao進行操作,而忽略Object o參數(shù)傳入的proxy.

有點遺憾, intercept函數(shù)里MethodProxy的Signature是固定的 , 即客戶如果調(diào)用foo(String),你不可以用proxy.invoke偷換成foo(String,String);


系列文章:
Java下的框架編寫(1)--序
Java下的框架編程(2)-對泛型的無聊用法和為擦拭法站臺?
Java下的框架編程(3)--關于反射的碎話?
Java下的框架編程(4)--Annotation vs XML vs Interface 最新一Round?
Java下的框架編程(5)--cglib應用
Java下的框架編程(6)--asm(待寫)