责任链设计模式实战系列(二)

文章介绍了SpringMVC中Interceptor的实现原理,包括Interceptor接口、InterceptorRegistry类用于注册和配置拦截器、MappedInterceptor处理生效条件以及HandlerExecutionChain执行链的核心代码。示例展示了如何添加和使用拦截器,并通过测试用例解释了拦截器的执行流程和顺序。
摘要由CSDN通过智能技术生成

前言

  1. 这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。

  2. 这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。

  3. 我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握。

  4. 欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/

  5. 上一小节我们分析了 Tomcat 的 Filter 设计,这一小节我们来分析 SpringMVC 的 Interceptor 设计

  6. 本系列 Github 地址:https://github.com/lijunping365/Open-Design

SpringMVC 之 Interceptor

下面的代码是我对 SpringMVC 的 Interceptor 提炼之后的核心代码。

  1. 拦截器接口
public interface HandlerInterceptor {

    default boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
    }

    default void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
    }
}

参数

public class HttpRequest {
}
public class HttpResponse {
}

下面三个类主要对拦截器进行排序和生效条件设置

public class InterceptorRegistry {

    private final List<InterceptorRegistration> registrations = new ArrayList<>();

    /**
     * Adds the provided {@link org.springframework.web.servlet.HandlerInterceptor}.
     * @param interceptor the interceptor to add
     * @return an {@link InterceptorRegistration} that allows you optionally configure the
     * registered interceptor further for example adding URL patterns it should apply to.
     */
    public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
        InterceptorRegistration registration = new InterceptorRegistration(interceptor);
        this.registrations.add(registration);
        return registration;
    }

    /**
     * Return all registered interceptors.
     */
    public List<Object> getInterceptors() {
        return this.registrations.stream()
                .sorted(INTERCEPTOR_ORDER_COMPARATOR)
                .map(InterceptorRegistration::getInterceptor)
                .collect(Collectors.toList());
    }


    private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR =
            OrderComparator.INSTANCE.withSourceProvider(object -> {
                if (object instanceof InterceptorRegistration) {
                    return (Ordered) ((InterceptorRegistration) object)::getOrder;
                }
                return null;
            });
}
public class InterceptorRegistration {

    private final HandlerInterceptor interceptor;

    private List<String> includeCondition;

    private List<String> excludeCondition;

    private int order = 0;

    public InterceptorRegistration(HandlerInterceptor interceptor) {
        this.interceptor = interceptor;
    }

    public InterceptorRegistration order(int order) {
        this.order = order;
        return this;
    }

    protected int getOrder() {
        return this.order;
    }

    protected Object getInterceptor() {
        if (this.includeCondition == null && this.excludeCondition == null) {
            return this.interceptor;
        } else {
            return new MappedInterceptor(includeCondition, excludeCondition, this.interceptor);
        }
    }

    public InterceptorRegistration addIncludeConditions(String... conditions) {
        return this.addIncludeConditions(Arrays.asList(conditions));
    }

    public InterceptorRegistration addIncludeConditions(List<String> conditions) {
        this.includeCondition = this.includeCondition != null ? this.includeCondition : new ArrayList(conditions.size());
        this.includeCondition.addAll(conditions);
        return this;
    }

    public InterceptorRegistration addExcludeConditions(String... patterns) {
        return this.addExcludeConditions(Arrays.asList(patterns));
    }

    public InterceptorRegistration addExcludeConditions(List<String> patterns) {
        this.excludeCondition = this.excludeCondition != null ? this.excludeCondition : new ArrayList(patterns.size());
        this.excludeCondition.addAll(patterns);
        return this;
    }
}
public class MappedInterceptor implements HandlerInterceptor{

    private final List<String> includeConditions;

    private final List<String> excludeConditions;

    private final HandlerInterceptor interceptor;

    public MappedInterceptor(List<String> includeConditions, List<String> excludeConditions, HandlerInterceptor interceptor) {
        this.includeConditions = includeConditions;
        this.excludeConditions = excludeConditions;
        this.interceptor = interceptor;
    }

    public boolean matches(String parameter) {
        if (StringUtils.isBlank(parameter)){
            return false;
        }
        return includeConditions.contains(parameter) && !excludeConditions.contains(parameter);
    }

    public HandlerInterceptor getInterceptor() {
        return interceptor;
    }
}

拦截器链,这个是核心了

public class HandlerExecutionChain {

    private final Object handler;

    private List<HandlerInterceptor> interceptorList = new ArrayList<>();

    private int interceptorIndex = -1;

    public HandlerExecutionChain(Object handler) {
        this.handler = handler;
    }

    /**
     * Add the given interceptor to the end of this chain.
     */
    public void addInterceptor(HandlerInterceptor interceptor) {
        interceptorList.add(interceptor);
    }

    /**
     * Add the given interceptor at the specified index of this chain.
     * @since 5.2
     */
    public void addInterceptor(int index, HandlerInterceptor interceptor) {
        interceptorList.add(index, interceptor);
    }

    public List<HandlerInterceptor> getInterceptors() {
        return this.interceptorList;
    }


    /**
     * Apply preHandle methods of registered interceptors.
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     */
    public boolean applyPreHandle(HttpRequest request, HttpResponse response) throws Exception {
        List<HandlerInterceptor> interceptors = getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.size(); i++) {
                HandlerInterceptor interceptor = interceptors.get(i);
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

    /**
     * Apply postHandle methods of registered interceptors.
     */
    public void applyPostHandle(HttpRequest request, HttpResponse response, Object obj) throws Exception {
        List<HandlerInterceptor> interceptors = getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            for (int i = interceptors.size() - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors.get(i);
                interceptor.postHandle(request, response, this.handler, obj);
            }
        }
    }

    /**
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation
     * has successfully completed and returned true.
     */
    public void triggerAfterCompletion(HttpRequest request, HttpResponse response, Exception ex) throws Exception {
        List<HandlerInterceptor> interceptors = getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors.get(i);
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    System.out.println("HandlerInterceptor.afterCompletion threw exception" + ex2.getMessage());
                }
            }
        }
    }
}
public class HandlerMethod {

    private final Object bean;

    private final Class<?> beanType;

    private final Method method;

    private final Object[] arguments;

    public HandlerMethod(Object bean, Class<?> beanType, Method method, Object[] arguments) {
        this.bean = bean;
        this.beanType = beanType;
        this.method = method;
        this.arguments = arguments;
    }

    public Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(method);
        try {
            return method.invoke(bean, args);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }
}

测试

public class DemoService {
    public String test(){
        return "11111111111111111111";
    }
}
public class FirstInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor 前置");
        return true;
    }

    @Override
    public void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
        System.out.println("FirstInterceptor 处理中");
    }

    @Override
    public void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor 后置");
    }
}
public class SecondInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpRequest request, HttpResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor 前置");
        return true;
    }

    @Override
    public void postHandle(HttpRequest request, HttpResponse response, Object handler, Object obj) throws Exception {
        System.out.println("SecondInterceptor 处理中");
    }

    @Override
    public void afterCompletion(HttpRequest request, HttpResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondInterceptor 后置");
    }
}
public class InterceptorTest {
    public static void main(String[] args) throws Exception {
        InterceptorRegistry registry = new InterceptorRegistry();

        registry.addInterceptor(new FirstInterceptor())
                .addIncludeConditions("aaa")
                .addExcludeConditions("bbb")
                .order(1);

        registry.addInterceptor(new SecondInterceptor())
                .addIncludeConditions("aaa")
                .addExcludeConditions("ddd")
                .order(2);

        List<Object> interceptors = registry.getInterceptors();

        dispatcher((List<HandlerInterceptor>)(List)interceptors);
    }

    private static void dispatcher(List<HandlerInterceptor> interceptors) throws Exception {

        HandlerMethod handlerMethod = new HandlerMethod(new DemoService(), DemoService.class, DemoService.class.getMethod("test", null), null);

        HandlerExecutionChain chain = new HandlerExecutionChain(handlerMethod);

        for (HandlerInterceptor interceptor : interceptors) {
            if (interceptor instanceof MappedInterceptor){
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches("aaa")) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            } else{
                chain.addInterceptor(interceptor);
            }
        }

        HttpRequest request = new HttpRequest();
        HttpResponse response = new HttpResponse();

        Exception exception = null;
        try {
            final boolean b = chain.applyPreHandle(request, response);
            if (!b){
                return;
            }

            // invoke 原方法
            Object o = handlerMethod.doInvoke(null);
            System.out.println(o);

            chain.applyPostHandle(request, response, o);
        }catch (Exception e){
            exception = e;
            System.out.println(e.getMessage());
        }
        chain.triggerAfterCompletion(request, response, exception);
    }
}

输出结果

FirstInterceptor 前置
SecondInterceptor 前置
11111111111111111111
SecondInterceptor 处理中
FirstInterceptor 处理中
SecondInterceptor 后置
FirstInterceptor 后置

你可以修改拦截器的顺序或者修改拦截器的生效条件去测试,还有你也可以将某个拦截器的 preHandle 方法返回 false 去查看测试结果

欢迎在评论区留下你的总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值