第三十八章 Spring之假如让你来写MVC——适配器篇

Spring源码阅读目录

第一部分——IOC篇

第一章 Spring之最熟悉的陌生人——IOC
第二章 Spring之假如让你来写IOC容器——加载资源篇
第三章 Spring之假如让你来写IOC容器——解析配置文件篇
第四章 Spring之假如让你来写IOC容器——XML配置文件篇
第五章 Spring之假如让你来写IOC容器——BeanFactory和FactoryBean
第六章 Spring之假如让你来写IOC容器——Scope和属性填充
第七章 Spring之假如让你来写IOC容器——属性填充特别篇:SpEL表达式
第八章 Spring之假如让你来写IOC容器——拓展篇
第九章 Spring之源码阅读——环境搭建篇
第十章 Spring之源码阅读——IOC篇

第二部分——AOP篇

第十一章 Spring之不太熟的熟人——AOP
第十二章 Spring之不得不了解的内容——概念篇
第十三章 Spring之假如让你来写AOP——AOP联盟篇
第十四章 Spring之假如让你来写AOP——雏形篇
第十五章 Spring之假如让你来写AOP——Joinpoint(连接点)篇
第十六章 Spring之假如让你来写AOP——Pointcut(切点)篇
第十七章 Spring之假如让你来写AOP——Advice(通知)上篇
第十八章 Spring之假如让你来写AOP——Advice(通知)下篇
第十九章 Spring之假如让你来写AOP——番外篇:Spring早期设计
第二十章 Spring之假如让你来写AOP——Aspect(切面)篇
第二十一章 Spring之假如让你来写AOP——Weaver(织入器)篇
第二十二章 Spring之假如让你来写AOP——Target Object(目标对象)篇
第二十三章 Spring之假如让你来写AOP——融入IOC容器篇
第二十四章 Spring之源码阅读——AOP篇

第三部分——事务篇

第二十五章 Spring之曾经的老朋友——事务
第二十六章 Spring之假如让你来写事务——初稿篇
第二十七章 Spring之假如让你来写事务——铁三角篇
第二十八章 Spring之假如让你来写事务——属性篇
第二十九章 Spring之假如让你来写事务——状态篇
第三十章 Spring之假如让你来写事务——管理篇
第三十一章 Spring之假如让你来写事务——融入IOC容器篇
第三十二章 Spring之源码阅读——事务篇

第四部分——MVC篇

第三十三章 Spring之梦开始的地方——MVC
第三十四章 Spring之假如让你来写MVC——草图篇
第三十五章 Spring之假如让你来写MVC——映射器篇
第三十六章 Spring之假如让你来写MVC——拦截器篇
第三十七章 Spring之假如让你来写MVC——控制器篇
第三十八章 Spring之假如让你来写MVC——适配器篇
第三十九章 Spring之假如让你来写MVC——番外篇:类型转换
第四十章 Spring之假如让你来写MVC——ModelAndView篇
第四十一章 Spring之假如让你来写MVC——番外篇:数据绑定
第四十二章 Spring之假如让你来写MVC——视图篇
第四十三章 Spring之假如让你来写MVC——上传文件篇
第四十四章 Spring之假如让你来写MVC——异常处理器篇
第四十五章 Spring之假如让你来写MVC——国际化篇
第四十六章 Spring之假如让你来写MVC——主题解析器篇
第四十七章 Spring之假如让你来写MVC——闪存管理器篇
第四十八章 Spring之假如让你来写MVC——请求映射视图篇
第四十九章 Spring之假如让你来写MVC——番外篇:属性操作
第五十章 Spring之假如让你来写MVC——融入IOC容器篇
第五十一章 Spring之源码阅读——MVC篇



前言

    对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
在这里插入图片描述

    所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》


     书接上回,在上篇 第三十七章 Spring之假如让你来写MVC——控制器篇 中,A君 已经完成了 控制器 部分的功能了。接下来看看 A君 会有什么骚操作吧

尝试动手写IOC容器

    出场人物:A君(苦逼的开发)、老大(项目经理)

    背景:老大 要求 A君在一周内开发个简单的 IOC容器

    前情提要:A君 已经完成了 控制器 部分的功能了 。。。

第三十四版 适配器

    “A君 呐,你用if..else来判断调用哪个处理器就很灵性了。” 老大 感叹道

    “额。” A君 不知道怎么结果话茬,只能装傻充愣了

    “这种拓展性太低了,后边还有其他处理器的实现方式呢。这样子往后稍微发展下,你的代码就变成了传说中的 屎山代码。还有一点,就是关于请求参数的处理,要知道一个请求可以携带很多参数的,而你现在这个实现,用户只能去request里获取,这一点用户体验非常的糟糕。去把这两部部分内容处理下吧。” 说完,老大 就没再说什么了

    看到 老大 没有继续往下说的意思,看来是要自己发挥。A君 默默的退了出去,准备着手干活了

    对于这种类型适配器,A君 其实并不算陌生,早在之前实现 IOC容器 的时候,A君 就已经接触过,只不过当时是根据属性类型找到对应的转换器进行类型转换。而这次,只是改成根据不同的 控制器 找到对应的 适配器 而已,其本质本无实际上的区别。那么 适配器 的接口就好定义了,必然存在着两个方法,一个是能不能转换,另一个是进行转换。基本盘有了,接下来就要考虑特殊性了,由于HTTP中定义了Last-Modified。其规范如下:

在这里插入图片描述

这个属性跟缓存息息相关,如果没有超过对应时间,则服务器可以直接不处理,返回上次结果。那么整体的接口定义就出来了,A君 新增HandlerAdapter接口,代码如下:

/**
 * 控制器的适配器,找到对应的控制器
 */
public interface HandlerAdapter {
   
    /**
     * 是否可以转换
     *
     * @param handler
     * @return
     */
    boolean supports(Object handler);

    /**
     * 处理请求
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    /**
     * 如果没有默认实现,默认返回-1
     * 这个方法放在这里感觉并不合适,LastModified和适配器并有什么关系,违反了接口单一原则,并不符合Spring一贯的作风
     * 新版本已经弃用,这里考虑到老项目
     *
     * @param request
     * @param handler
     * @return
     */
    @Deprecated
    long getLastModified(HttpServletRequest request, Object handler);
}

Last-Modified的处理方法放在这里感觉并不合适,Last-Modified和适配器本身并没有什么关系,违反了接口单一原则。按理说,适配器只负责找到处理对应的控制器进行处理,并不会去关心Last-Modified这些东西,此处的设计不符合Spring一贯的作风,不知道当初是基于什么考虑才如此设计,这里为了贴近Spring,所以也加上getLastModified方法。在Spring5.3.9后续版本中,该方法已经标记成弃用

好了,接口出来后,先挑个简单的练练手,A君 盯上了ControllerServlet,原因也简单,实现了对应接口的,其实是最好处理的,只需要强转后调用该接口方法就行了。这里 A君 就以Controller适配器为例,新增SimpleControllerHandlerAdapter类,代码如下:

/**
 * Controller相关接口适配
 */
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
   

    @Override
    public boolean supports(Object handler) {
   
        return (handler instanceof Controller);
    }

    @Override
    public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
   

        return ((Controller) handler).handleRequest(request, response);
    }

    @Override
    @SuppressWarnings("deprecation")
    public long getLastModified(HttpServletRequest request, Object handler) {
   
        if (handler instanceof LastModified) {
   
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

    简单过后,A君 就开始头疼了,简单之所以简单,是因为实现了对应接口,方法参数、返回值都是固定的。而基于注解的 控制器,这两个没有一个是能确定的,不能确定就意味着:需要框架去推算匹配,那么参数处理就会变得异常的麻烦。没办法,只能先易后难。A君 谨遵 老大 的教诲,对于有公共内容的,提取出来一个抽象类。于是,A君 新增AbstractHandlerMethodAdapter类,代码如下:

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
   

    @Override
    public final boolean supports(Object handler) {
   
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

    @Override
    public final Object handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
   

        return handleInternal(request, response, (HandlerMethod) handler);
    }

    protected abstract Object handleInternal(HttpServletRequest request,
                                             HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

    protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

    @Override
    @SuppressWarnings("deprecation")
    public final long getLastModified(HttpServletRequest request, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穷儒公羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值