所謂的業(yè)務(wù)方法調(diào)用攔截就是業(yè)務(wù)方法在調(diào)用前或后我們可以插入自己的業(yè)務(wù)代碼進行攔截處理,如果我們需要在操作人員在操作我們的業(yè)務(wù)模塊時,記錄操作人員的操作日志,那么就可以通過該功能實現(xiàn)。在BDF2當(dāng)中,我們通過Spring的AOP方法攔截提供了名為IMethodInterceptor接口,開發(fā)人員可以通過實現(xiàn)該接口將其配置到Spring當(dāng)中即可,IMethodInterceptor接口源碼如下:
IMethodInterceptor接口源碼
package com.bstek.bdf2.core.aop;
import java.lang.reflect.Method;
/**
* 實現(xiàn)該接口用于攔截用戶感興趣的業(yè)務(wù)方法調(diào)用,比如作業(yè)務(wù)操作審計等
* @author Jacky.gao
* @since 2013年7月11日
*/
public interface IMethodInterceptor {
/**
* 是否支持當(dāng)前方法調(diào)用
* @param objectClass 調(diào)用類class
* @param method 調(diào)用的方法對象
* @return true表示支持,false表示不支持
*/
boolean support(Class<?> objectClass,Method method);
/**
* 在方法調(diào)用之前攔截,如不需要保持實現(xiàn)類中該方法為空即可
* @param objectClass 調(diào)用類class
* @param method 調(diào)用的方法對象
* @param arguments 方法調(diào)用時采用的參數(shù)集合
* @throws Exception
*/
void doBefore(Class<?> objectClass,Method method,Object[] arguments) throws Exception;
/**
* 在方法調(diào)用之后攔截,如不需要保持實現(xiàn)類中該方法為空即可
* @param objectClass 調(diào)用類class
* @param method 調(diào)用的方法對象
* @param arguments 方法調(diào)用時采用的參數(shù)集合
* @param returnValue 方法調(diào)用完成后的返回值
* @throws Exception
*/
void doAfter(Class<?> objectClass,Method method,Object[] arguments,Object returnValue) throws
Exception;
}
需要注意的是,在使用IMethodInterceptor接口時,我們還需要定義bdf2.globalMethodIntercetporBeanNamesPattern屬性,通過該屬性來決定我們AOP實現(xiàn)要攔截哪些bean的方法調(diào)用,如果不定義該屬性,那么默認將不攔截任何bean的方法調(diào)用,比如我們可以在
dorado-home/configure.properties文件當(dāng)中將bdf2.globalMethodIntercetporBeanNamesPattern屬性值設(shè)置為"*Maintain,*Dao",那么就表示將攔截所有bean的id以Maintain結(jié)尾的或以Dao結(jié)尾的bean的方法調(diào)用??梢钥吹皆谶@個屬性值定義時多個值需要用逗號分隔。
下圖當(dāng)中我將在dorado-home/configure.properties文件當(dāng)中將bdf2.globalMethodIntercetporBeanNamesPattern屬性值設(shè)置為"*Maintain,*Dao":
同時我們編寫了一個名為TestMethodInterceptor的IMethodInterceptor接口實現(xiàn)類,其源碼如下:
TestMethodInterceptor源碼
package test;
import java.lang.reflect.Method;
import org.springframework.stereotype.Component;
import com.bstek.bdf2.core.aop.IMethodInterceptor;
import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.view.user.UserMaintain;
@Component
public class TestMethodInterceptor implements IMethodInterceptor {
public boolean support(Class<?> objectClass, Method method) {
if(objectClass.getName().equals(UserMaintain.class.getName())){
return true;
}
return false;
}
public void doBefore(Class<?> objectClass, Method method, Object[] arguments)
throws Exception {
System.out.println("......before invoke:"+method.getName());
System.out.println("......login user:"+ContextHolder.getLoginUserName());
}
public void doAfter(Class<?> objectClass, Method method,
Object[] arguments, Object returnValue) throws Exception {
System.out.println("......after invoke:"+method.getName());
System.out.println("......return value:"+returnValue);
System.out.println("......arguments:"+arguments);
}
}
啟動服務(wù),登錄后訪問BDF2當(dāng)中的用戶維護界面,可以看到控制臺輸出的相關(guān)攔截信息。
注意事項
設(shè)置bdf2.globalMethodIntercetporBeanNamesPattern屬性值,就是在決定應(yīng)該攔截哪些springbean的方法調(diào)用。在我們的Spring環(huán)境當(dāng)中,有各種類型的Bean存在,對于我們這里的bean方法調(diào)用攔截功能來說,要求可以攔截的bean一定要有一個空的構(gòu)造方法,如果我們設(shè)置的bdf2.globalMethodIntercetporBeanNamesPattern屬性值,與Spring當(dāng)中一個沒有空構(gòu)造方法的Bean匹配,那么就會出現(xiàn)下面的異常:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
這個異常就是在提示我們當(dāng)前攔截到的Spring bean沒有空的構(gòu)造方法,所以拋出這么一個異常。我們當(dāng)前提供攔截操作基于CGLib代理實現(xiàn),所以也進一步說明CGLib 代理實現(xiàn)調(diào)用攔截,要求匹配的Bean一定要有一個空的構(gòu)造方法。
在BDF2當(dāng)中,提供的與頁面操作相關(guān)的bean皆以Maintain結(jié)尾,所以在設(shè)置bdf2.globalMethodIntercetporBeanNamesPattern屬性值的時候只要包含"*Maintain"就可以攔截所有BDF2當(dāng)中頁面交互操作產(chǎn)生的方法調(diào)用。同時我們也建議您在業(yè)務(wù)模塊開發(fā)時,與前臺交互的Bean的id在命名是以Maintain結(jié)尾,比如UserMaintain,這就是一個用戶維護的bean。
如果您不愿采用Maintain結(jié)尾,我們也強烈建議您采用一個固定字符串作為bean的id結(jié)尾,比如BO,用于用戶維護操作的bean相應(yīng)就是UserBO。一旦采用這種原則我們就可以將bdf2.globalMethodIntercetporBeanNamesPattern屬性值設(shè)置為"*Maintain,*BO",這樣既可以攔截BDF2當(dāng)中所有頁面操作方法調(diào)用,也可以攔截我們業(yè)務(wù)模塊頁面當(dāng)中的方法調(diào)用。
更多建議: