BSTEK Development Framework2(BDF2) : 3.11.业务方法调用拦截

       所谓的业务方法调用拦截就是业务方法在调用前或后我们可以插入自己的业务代码进行拦截处理,如果我们需要在操作人员在操作我们的业务模块时,记录操作人员的操作日志,那么就可以通过该功能实现。在BDF2当中,我们通过Spring的AOP方法拦截提供了名为IMethodInterceptor接口,开发人员可以通过实现该接口将其配置到Spring当中即可,IMethodInterceptor接口源码如下:

IMethodInterceptor接口源码
package com.bstek.bdf2.core.aop;
import java.lang.reflect.Method;
/**
 * 实现该接口用于拦截用户感兴趣的业务方法调用,比如作业务操作审计等
 * @author Jacky.gao
 * @since 2013年7月11日
 */
public interface IMethodInterceptor {
	/**
	 * 是否支持当前方法调用
	 * @param objectClass 调用类class
	 * @param method 调用的方法对象
	 * @return true表示支持,false表示不支持
	 */
	boolean support(Class<?> objectClass,Method method);
	/**
	 * 在方法调用之前拦截,如不需要保持实现类中该方法为空即可
	 * @param objectClass 调用类class
	 * @param method 调用的方法对象
	 * @param arguments 方法调用时采用的参数集合
	 * @throws Exception
	 */
	void doBefore(Class<?> objectClass,Method method,Object[] arguments) throws Exception;
	/**
	 * 在方法调用之后拦截,如不需要保持实现类中该方法为空即可
	 * @param objectClass 调用类class
	 * @param method 调用的方法对象
	 * @param arguments 方法调用时采用的参数集合
	 * @param returnValue 方法调用完成后的返回值
	 * @throws Exception
	 */
	void doAfter(Class<?> objectClass,Method method,Object[] arguments,Object returnValue) throws Exception;
}

       需要注意的是,在使用IMethodInterceptor接口时,我们还需要定义bdf2.globalMethodIntercetporBeanNamesPattern属性,通过该属性来决定我们AOP实现要拦截哪些bean的方法调用,如果不定义该属性,那么默认将不拦截任何bean的方法调用,比如我们可以在dorado-home/configure.properties文件当中将bdf2.globalMethodIntercetporBeanNamesPattern属性值设置为"*Maintain,*Dao",那么就表示将拦截所有bean的id以Maintain结尾的或以Dao结尾的bean的方法调用。可以看到在这个属性值定义时多个值需要用逗号分隔。

       下图当中我将在在dorado-home/configure.properties文件当中将bdf2.globalMethodIntercetporBeanNamesPattern属性值设置为"*Maintain,*Dao":

       同时我们编写了一个名为TestMethodInterceptor的IMethodInterceptor接口实现类,其源码如下:

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);
	}
}

      启动服务,登录后访问BDF2当中的用户维护界面,可以看到控制台输出的相关拦截信息。

注意事项

设置bdf2.globalMethodIntercetporBeanNamesPattern属性值,就是在决定应该拦截哪些spring bean的方法调用。在我们的Spring环境当中,有各种类型的Bean存在,对于我们这里的bean方法调用拦截功能来说,要求可以拦截的bean一定要有一个空的构造方法,如果我们设置的bdf2.globalMethodIntercetporBeanNamesPattern属性值,与Spring当中一个没有空构造方法的Bean匹配,那么就会出现下面的异常:

java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

这个异常就是在提示我们当前拦截到的Spring bean没有空的构造方法,所以抛出这么一个异常。我们当前提供拦截操作基于CGLib 代理实现,所以也进一步说明CGLib 代理实现调用拦截,要求匹配的Bean一定要有一个空的构造方法。

在BDF2当中,提供的与页面操作相关的bean皆以Maintain结尾,所以在设置bdf2.globalMethodIntercetporBeanNamesPattern属性值的时候只要包含"*Maintain"就可以拦截所有BDF2当中页面交互操作产生的方法调用。同时我们也建议您在业务模块开发时,与前台交互的Bean的id在命名是以Maintain结尾,比如UserMaintain,这就是一个用户维护的bean。

如果您不愿采用Maintain结尾,我们也强烈建议您采用一个固定字符串作为bean的id结尾,比如BO,用于用户维护操作的bean相应就是UserBO。一旦采用这种原则我们就可以将bdf2.globalMethodIntercetporBeanNamesPattern属性值设置为"*Maintain,*BO",这样既可以拦截BDF2当中所有页面操作方法调用,也可以拦截我们业务模块页面当中的方法调用。

Attachments:

property-set.png (image/png)