Java知识总结----Spring拦截器(六)

在看到拦截器的时候,大家一定会想到另外一个词,就是过滤器。两者到底有什么区别呢?过滤器,从字面的意思理解就是过滤用的,当很多请求过来的时候,我们对其进行过滤,满足一定条件的时候,才放行。在Java中,过滤器是使用Filter实现的,实现原理都是基于回调函数的。最常见的过滤器的应用就是字符编码的过滤、用户信息验证的过滤等。拦截器呢,就是用来拦截的,可以在方法的执行时,添加一些其他的信息,拦截器是使用Interceptor实现的,实现原理是基于Java的反射机制的。最常见的拦截器的应用有:添加访问日志、性能监控等。今天我们就来看看怎么用Spring的拦截器为方法添加访问日志。

首先,我们创建一个拦截器类,由于我们需要拦截的是方法,所以,就继承MethodInterceptor类。

 

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 监控日志拦截器
 * @author lizhiyang
 *
 */
public class MonitorLogInterceptor implements MethodInterceptor {
	
	private Logger logger = LoggerFactory.getLogger(MonitorLogInterceptor.class);

	public Object invoke(MethodInvocation methodinvocation) throws Throwable {
		Method method = methodinvocation.getMethod();
		//方法执行前输出
		logger.info("methodIn:methodName="+method.getName());
		try {
			//执行方法
			return methodinvocation.proceed();
		} finally {
			//方法执行后输出
			logger.info("methodOut:methodName="+method.getName());
		}
	}

}


在方法的执行前和执行后都加上日志输出。

 

接着,有的时候,我们可能需要自定义多个拦截器,这个时候,我们需要有一个拦截器链,把这些拦截器都串起来。

 

import java.util.ArrayList;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 拦截器链
 * @author lizhiyang
 *
 */
public class InterceptorChain implements MethodInterceptor {

	private List<MethodInterceptor> chains;
	
	public Object invoke(MethodInvocation methodinvocation) throws Throwable {
		InterceptorChainSupport support = new InterceptorChainSupport(methodinvocation, new ArrayList<MethodInterceptor>(chains));
		return support.proceed();
	}

	public List<MethodInterceptor> getChains() {
		return chains;
	}
	
	public void setChains(List<MethodInterceptor> chains) {
		this.chains = chains;
	}
}

 

里面我们用到了一个类:InterceptorChainSupport,他的实现如下:

 

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class InterceptorChainSupport implements MethodInvocation {
	
	private MethodInvocation proxy;
	private List<MethodInterceptor> chains;
	
	public InterceptorChainSupport(MethodInvocation proxy,List<MethodInterceptor> chains) {
		this.proxy = proxy;
		this.chains = chains;
	}

	public MethodInvocation getProxy() {
		return proxy;
	}

	public void setProxy(MethodInvocation proxy) {
		this.proxy = proxy;
	}

	public List<MethodInterceptor> getChains() {
		return chains;
	}

	public void setChains(List<MethodInterceptor> chains) {
		this.chains = chains;
	}

	public Object[] getArguments() {
		return proxy.getArguments();
	}

	public AccessibleObject getStaticPart() {
		return proxy.getStaticPart();
	}

	public Object getThis() {
		return proxy.getThis();
	}

	public Object proceed() throws Throwable {
		//如果拦截器链不空,则继续执行拦截器
		if(chains != null && chains.size() > 0) {
			//递归调用,一直调用到拦截器链的最后一个
			return (chains.remove(0)).invoke(this);
		} else {
			return proxy.proceed();
		}
	}

	public Method getMethod() {
		return proxy.getMethod();
	}
}

 

InterceptorChainSupport是真正来处理拦截器链的,遍历执行所有的拦截器。在InterceptorChain中构造InterceptorChainSupport的时候要特别注意,一定要new一个新的List来存放chains,否则,会造成调用链只能执行一次的情况。

此处的执行过程是这样的:当调用相应的方法时,调用InterceptorChain.invoke()----->InterceptorChainSupport.proceed()---->***Interceptor.invoke()------>InterceptorChainSupport().proceed()------......---->真正的方法处理---->方法之后的拦截处理。

 

最后,我们在spring的配置文件中,来配置拦截器。

 

 

<!-- 配置日志监控拦截器 -->
	<bean id="monitorLogInterceptor" class="com.demo.interceptor.MonitorLogInterceptor" />
	
	<!-- 配置拦截器链,保存所有的拦截器 -->
	<bean id="interceptorChain" class="com.demo.interceptor.InterceptorChain">
		<property name="chains">
			<list>
				<ref bean="monitorLogInterceptor"/>
			</list>
		</property>
	</bean>
	
	<!-- 配置拦截器和需要拦截的bean -->
	<bean id="serviceProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="interceptorNames">
			<list>
				<value>interceptorChain</value>
			</list>
		</property>
		<property name="beanNames">
			<value>*Service</value>
		</property>
	</bean>


这样配置之后,在spring容器加载的时候,spring就知道了执行*Service类中的方法时候,需要应用interceptorChain中的拦截器。

 

这个时候呢,就有了一个问题,如果我不想给这个类的每个方法都进行拦截,只拦截一部分呢?这个时候我们可以借助注解来实现。为需要拦截的方法上加上注解。

首先我们创建一个注解类,MonitorLog。

 

/**
 * 	1.RetentionPolicy.SOURCE ——只在源代码级别保留,编译时就会被忽略
	2.RetentionPolicy.CLASS ——编译时被保留,在class文件中存在,但JVM将会忽略
	3.RetentionPolicy.RUNTIME —— 被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
 *
 */
@Retention(RetentionPolicy.RUNTIME)
/**
 * 该注解应用于方法
 */
@Target(ElementType.METHOD)
/**
 * 指明被注解的类会自动继承,如果我们把注解放在接口的方法上,那么实现该接口的类也会被继承该注解
 */
@Inherited
/**
 * Documented 注解表明这个注解应该被 javadoc工具记录.
 */
@Documented
public @interface MonitorLog {

}


然后我们在需要拦截的方法上天剑@MonitorLog注解。

 

 

public interface UserService {
	@MonitorLog
	public boolean insertUser(UserModel user);
	public UserModel getUser(int userId);
	public String test();
	public void user(String name);
}


我们现在还需要修改MonitorLogInterceptor类,只有添加@MonitorLog的方法才进行拦截,其他的不拦截。

 

 

public class MonitorLogInterceptor implements MethodInterceptor {
	
	private Logger logger = LoggerFactory.getLogger(MonitorLogInterceptor.class);

	public Object invoke(MethodInvocation methodinvocation) throws Throwable {
		Method method = methodinvocation.getMethod();
		//获取方法的MonitorLog注解
		MonitorLog log = method.getAnnotation(MonitorLog.class);
		boolean bLog = false;
		//该方法存在MonitorLog注解,则输出日志
		if(log != null) {
			bLog = true;
			//方法执行前输出
			logger.info("methodIn:methodName="+method.getName());
		}
		try {
			//执行方法
			return methodinvocation.proceed();
		} finally {
			if(bLog) {
				//方法执行后输出
				logger.info("methodOut:methodName="+method.getName());
			}
		}
	}

}


以上,就是spring拦截器的一个简单的应用。当然了,我们也可以使用spring的aop标签,来进行具体的配置。

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

你可能感兴趣的:(java,拦截器,Interceptor)