应用 | 责任链模式(拦截器)

       之前有初步认识了责任链这种设计模式,在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);
    }

  

        测试结果和预期一样,完成了功能需求,并且后期维护可以针对性的去扩展相应的功能,很大程度降低了代码的耦合性,方便了后期的扩展和修改。希望大家能够有所收获。

猜你喜欢

转载自blog.csdn.net/a_ll1203/article/details/81081524