之前有初步认识了责任链这种设计模式,在springMvc中拦截器就是责任链模式的一种应用,为了更好的了解掌握责任链,我们看一下拦截器是如何实现的,之后仿照拦截器写一个自己的拦截器。
一、SpringMvc源码分析:
1, 拦截器的实现方式一般需要我们实现 HandlerInterceptor接口之后实现下面的三个方法,之后配置拦截器
// 该方法将在Controller处理之前进行调用
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
// postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
// 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
2,springMvc处理请求是通过DispatcherServlet来全局控制的,因为关注点在拦截器的实现,具体的处理分发在这里不做赘述,看一下关于拦截器部分的源码:
//为方便理解,此处有删减,如有需要可自行查看源码
HandlerExecutionChain mappedHandler = null;
// 处理前置拦截
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.(真正执行handler中方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 处理handler之后的拦截
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 处理后置拦截
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
这里发现spring是通过HandlerExecutionChain 来操作具体拦截的,通过名字可以发现是一个Handler链式的处理方式,preHandler是在handler之前执行,postHandler是在handler之后,渲染视图之后执行,afterCompletion是最后执行。
3, 查看HandlerExecutionChain来看一下spring是如何具体处理前置拦截和后置拦截的。
前置拦截部分
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
后置拦截部分
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
查看代码可知,spring将拦截器放在了一个List中取循环处理,前置拦截做正向循环,后置拦截做逆向循环,在前置拦截部分如果请求未通过返回false,跳转到后置拦截做处理。
spring的这种处理方式给了我们新的思考,每个拦截器有自己的具体功能,当我们需要修改具体的拦截方式时,只需要对当前拦截器部分的代码进行修改,不会对我们handler中代码有侵入性,也不会影响到后置处理的部分。handler和后置同理,很好的实现了代码的解耦。
二、责任链(拦截器)具体应用:
在开发过程中,经常会有很复杂的逻辑,在进行具体操作前需要进行很多的参数校验、逻辑校验、参数转换等等,全部的校验逻辑通过后才可以进行具体的操作,操作完成后可能又会有其他的通知、状态的修改、关联业务的处理等。随着业务和需求的变更后期的维护和扩展往往会伴随着一系列问题。正因为代码的耦合性太高,维护代码的成本变高,如果像spring拦截器一样,给具体业务做分层处理,前置操作、具体操作、后置操作将这些操作放在一条链上,各司其职,是不是会更好一点,且后期有新的需求校验进来,也可以像spring一样添加拦截器,配置拦截器,减少代码的改动和入侵。
1,设定需求:添加功能,校验不通过时不会走到添加的具体业务里面,添加的业务不成功时不会走到后置的操作里面
2,具体实现:
(1)实现添加的具体业务逻辑
@Service
public class AddServiceImpl implements AddService {
@Override
public boolean add(AddBO addBO) {
String addMsg = addBO.getAddMsg();
if (StringUtils.isBlank(addMsg)) return false;
System.out.println("添加消息:" + addMsg);
addBO.setResult("添加结果");
return true;
}
}
(2)写一个类似于HandlerInterceptor的接口
public interface AddInterceptorService {
/**
* 前置拦截
* @param addBO
* @return 默认返回true,放行当前拦截
*/
boolean preHandler(AddBO addBO);
/**
* 后置拦截
* @param addBO
*/
void afterHandler(AddBO addBO);
}
(3)实现Interceptor接口的具体处理逻辑
@Service("addInterceptorServiceOneImpl")
public class AddInterceptorServiceOneImpl implements AddInterceptorService {
@Override
public boolean preHandler(AddBO addBO) {
String preMsg1 = addBO.getPreMsg1();
if (StringUtils.isBlank(preMsg1)) return false;
System.out.println("拦截器1前置处理:" + preMsg1);
return true;
}
@Override
public void afterHandler(AddBO addBO) {
String result = addBO.getResult();
System.out.println("拦截器1后置处理:" + result);
}
}
@Service("addInterceptorServiceTwoImpl")
public class AddInterceptorServiceTwoImpl implements AddInterceptorService {
@Override
public boolean preHandler(AddBO addBO) {
String preMsg2 = addBO.getPreMsg2();
if (StringUtils.isBlank(preMsg2)) return false;
System.out.println("拦截器2前置处理:" + preMsg2);
return true;
}
@Override
public void afterHandler(AddBO addBO) {
String result = addBO.getResult();
System.out.println("拦截器2后置处理:" + result);
}
}
(4)实现类似DispatcherServlet和HandlerExecutionChain的功能逻辑(此处写到了一起)
@Service
public class AddExecutionChainImpl implements AddExecutionChain {
@Autowired
private AddService addService;
@Autowired
@Qualifier("addInterceptorServiceOneImpl")
private AddInterceptorService addInterceptorServiceOne;
@Autowired
@Qualifier("addInterceptorServiceTwoImpl")
private AddInterceptorService addInterceptorServiceTwo;
private List<AddInterceptorService> interceptorServiceList = new ArrayList<>();
/**
*在系统启动时初始化interceptor并加载到List中,后期可在此处进行扩展功能的配置
*/
@PostConstruct
public void init(){
interceptorServiceList.add(addInterceptorServiceOne);
interceptorServiceList.add(addInterceptorServiceTwo);
}
@Override
public void addChainAction(AddBO addBO) {
if (!doPreHandler(addBO)) return;
if (!addService.add(addBO)) return;
doAfterHandler(addBO);
}
private boolean doPreHandler(AddBO addBO) {
if (CollectionUtils.isEmpty(interceptorServiceList)) return false;
// 前置正序执行
for (AddInterceptorService preInterceptor: interceptorServiceList) {
if (!preInterceptor.preHandler(addBO)) {
return false;
}
}
return true;
}
private void doAfterHandler(AddBO addBO) {
if (CollectionUtils.isEmpty(interceptorServiceList)) return ;
// 后置倒序执行
for (int i = interceptorServiceList.size() - 1; i >= 0; i--) {
AddInterceptorService afterInterceptor = interceptorServiceList.get(i);
afterInterceptor.afterHandler(addBO);
}
}
}
(5)测试用例
@Test
public void addTest(){
AddBO addBO = new AddBO();
// addBO.setPreMsg1("前置消息1");
addBO.setPreMsg2("前置消息2");
addBO.setAddMsg("添加的消息");
addExecutionChain.addChainAction(addBO);
}
@Test
public void addTest(){
AddBO addBO = new AddBO();
addBO.setPreMsg1("前置消息1");
// addBO.setPreMsg2("前置消息2");
addBO.setAddMsg("添加的消息");
addExecutionChain.addChainAction(addBO);
}
@Test
public void addTest(){
AddBO addBO = new AddBO();
addBO.setPreMsg1("前置消息1");
addBO.setPreMsg2("前置消息2");
// addBO.setAddMsg("添加的消息");
addExecutionChain.addChainAction(addBO);
}
@Test
public void addTest(){
AddBO addBO = new AddBO();
addBO.setPreMsg1("前置消息1");
addBO.setPreMsg2("前置消息2");
addBO.setAddMsg("添加的消息");
addExecutionChain.addChainAction(addBO);
}
测试结果和预期一样,完成了功能需求,并且后期维护可以针对性的去扩展相应的功能,很大程度降低了代码的耦合性,方便了后期的扩展和修改。希望大家能够有所收获。