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源码阅读目录
- 前言
- 尝试动手写IOC容器
-
-
- [第三十二版 拦截器](#第三十二版 拦截器)
-
- 总结
前言
对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》
书接上回,在上篇 第三十五章 Spring之假如让你来写MVC------映射器篇 中,A君 已经实现了 映射器 部分的功能了。接下来看看 A君 会有什么骚操作吧
尝试动手写IOC容器
出场人物:A君 (苦逼的开发)、老大(项目经理)
背景:老大 要求 A君 在一周内开发个简单的 IOC容器
前情提要:A君 已经实现了 映射器 部分的功能了 。。。
第三十二版 拦截器
今天,刚一上班,A君 就屁颠屁颠的跑到 老大 的办公室去,炫耀自己的成果
"嗯。做的不错。不过还需要加点料?" 老大 看着满脸兴奋的 A君 。悠悠说道
"加点料,要加什么??" A君 兴奋地逐渐消失,一脸懵逼的问到
"你听说过 过滤器 吗?" 老大 微笑着问道
"听说过,过滤器 是 Servlet 规范中的一部分,所有 Servlet容器 都必须实现。请求在到达 Servlet 之前,或者响应返回客户端之前,都会经过 过滤器 进行处理。如果 过滤器 处理不通过,它可以阻止请求继续往下处理!" A君 回答道
"不错,现在要加的料和 过滤器 效果差不多,只是是框架层面的。叫做 拦截器 。" 老大 说到
"为什么有 过滤器 之后还需要 拦截器 呢?" A君 提出疑问
"问得好!原因其实也很简单。过滤器 是 Servlet容器 的行为,发生在 Servlet 之前,那么就以为这它无法获取框架中的内容,无法进行更细致的拦截。" 老大 笑着说道
"原来如此!" A君 恍然,之前一直存在的疑问,被 老大 三言两语就解开了
"去吧!这东西并不难,我希望今天就能看到成果!" 老大 大手一挥,开始下逐客令
拦截器接口
"OK!" A君 也爽快的回答道,离开办公室,回到自己的工位上。A君 想都没想,就开始撸代码,因为像这种提供拓展的功能,A君 只需要提供接口就行,具体内容由用户实现即可。A君 新增 HandlerInterceptor
接口,代码如下:
java
/**
* 拦截器接口
*/
public interface HandlerInterceptor {
/**
* 方法执行前调用
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/**
* 方法执行后调用
*
* @param request
* @param response
* @param handler
* @throws Exception
*/
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
/**
* 请求完成时调用,不管成功还是失败
*
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
好了,接口定义了完成了。不过要如何执行它的实现呢?老大 之前提到和 过滤器 类似,说起 过滤器 ,A君 其实并不算陌生,之前有折腾过 Tomcat ,知道其大致的运行流程。这里又得涉及到一个设计模式------责任链 。这个模式也好理解,就像 A君 平时想请个假,OA上需要经过层层审批,层层回复一样:
请假 同意 同意 同意 回复 回复 回复 回复 A君 项目经理 部门经理 技术总监 结束
每一层都得同意,这个假才算请成功,但凡有一个不同意,这个假就算是请失败了。值得注意的是:请假流程申请的时候是从前往后,而回复的时候却是从后往前的 。责任链 与之类似,既然如此,那么 拦截器 也就好办了:只要把 拦截器 整合成一个链表就可以了。A君 添加HandlerExecutionChain
类,代码如下:
java
/**
* 请求处理链
*/
@Getter
public class HandlerExecutionChain {
/**
* 控制器
*/
private final Object handler;
/**
* 拦截器集合
*/
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
private int interceptorIndex = -1;
/**
* 正向处理,类似与请假申请流程
*
* @param request
* @param response
* @return
* @throws Exception
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
//返回false,直接调用完成方法
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
/**
* 反向处理,类似与请假回复流程
*
* @param request
* @param response
* @throws Exception
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler);
}
}
/**
* 反向处理,类似与请假回复流程
*
* @param request
* @param response
* @throws Exception
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
ex2.printStackTrace();
}
}
}
//其他方法省略
}
改造映射器
确实如 老大 所说,拦截器 就这么点东西,没啥难度的。现在还需要改下 映射器 的返回值了,之前是直接返回HandlerMethod
,现在得返回HandlerExecutionChain
了,改动如下:
AbstractHandlerMapping
也做个简单的改动,需要把配置的 拦截器 添加到HandlerExecutionChain
中,如下:
改造DispatcherServlet
现在基本改造完了,还需要个添加 拦截器 的入口,只需要扫描类是否实现了对应接口就行了。DispatcherServlet
改动如下:
测试
好嘞,现在一切都准备就绪了。可以开始准备测试了,其他内容还是不需要改动。只需要新增一个 拦截器 即可,A君 新增MyInterceptor
。代码如下:
java
public class MyInterceptor implements HandlerInterceptor {
// 在请求处理前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre-handle: " + request.getRequestURI());
request.setAttribute("message", "Add Interceptor");
return true;
}
// 在请求处理后,视图渲染前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Post-handle: " + request.getRequestURI());
}
// 在请求完全处理完后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("After completion: " + request.getRequestURI());
}
}
添加测试代码如下:
java
@Test
public void v32() throws Throwable {
System.out.println("############# 第三十二版: 拦截器篇 #############");
Tomcat tomcat = new Tomcat();
//设置端口
tomcat.setPort(8082);
//设置静态资源路径
String webApp = new File("src/main/resources/v32").getAbsolutePath();
tomcat.addWebapp("/test/", webApp);
tomcat.start();
//挂起
tomcat.getServer().await();
}
测试结果如下:
前台成功返回,后台也成功打印。拦截器 也就这么完成啦。OK!起码今天可以交差了,看看 老大 明天还有什么想法吧
总结
正所谓树欲静而风不止,欲知后事如何,请看下回分解(✪ω✪)