天天看點

Java下的架構程式設計(5)--cglib的應用

2005年11月29日 10:51:00

作者: 江南白衣

反射、Proxy和中繼資料是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, 則原有類的每個方法調用都會轉為調用實作了MethodInterceptor接口的proxy的intercept() 函數:

public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)

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

AOP沒有出現以前,該領域經典的設計模式是Decorator,像Java IO Stream的設計就是如此.不過,如果為每個DAO, 每個方法的寫Decorator函數會寫死人的,是以用上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( " 調用日志方法 " + 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();建立子類執行個體,但在Spring管理下,一些Bean的執行個體必須由Spring來建立和管理,而不由enhancer來建立的。是以我對上述用法略加修改,使它真正當一個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( " 調用日志方法 " + method.getName());

Object result = proxy.invoke(dao, args);

return result;

}

}

可見,原來模式裡在getDao()時由enhancer建立dao,而 調用intercept時則将enhancer建立的dao以Object o參數傳回。

而新模式裡,dao在getDao()時從外面傳入,enhancer.create()傳回的是一個proxy. 而調用intercept時,實際會用之前傳入的dao進行操作,而忽略Object o參數傳入的proxy.

有點遺憾, intercept函數裡MethodProxy的Signature是固定的 , 即客戶如果調用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(待寫)

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=539013