09|分解Dispatcher:如何把专门的事情交给专门的部件去做?
两级 ApplicationContext
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何将Dispatcher进一步分解,让其专注于解析request请求,而将Bean的管理交给专门的Context来处理。作者首先提到了在程序结构上会有Controller和Service两层,计划将这两部分对应的容器进一步切割为XmlWebApplicationContext和AnnotationConfigWebApplicationContext。在DispatcherServlet类中增加了对WebApplicationContext的引用,命名为parentApplicationContext,用于区分Listener启动的上下文和DispatcherServlet启动的上下文。接着,作者详细介绍了对AnnotationConfigWebApplicationContext的改造,扩充了原有的构造方法,实现了对父上下文和servletContext的引用,并对DefaultListableBeanFactory进行了改造。同时,还对XmlWebApplicationContext进行了改造,实现了WebApplicationContext接口。最后,作者指出在Web环境下的两个ApplicationContext都构建完毕,WebApplicationContext持有对parentApplicationContext的单向引用。文章通过详细的代码解析和讲解,帮助读者了解了如何将Dispatcher进一步分解,实现了专门的事情交给专门的部件去做的目标。文章还介绍了如何通过新增RequestMappingHandlerMapping与RequestMappingHandlerAdapter来分别处理URL映射关系和映射后的处理过程,从而将DispatcherServlet的功能进行了分治,有利于今后的扩展。
《手把手带你写一个 MiniSpring》,新⼈⾸单¥59
全部留言(10)
- 最新
- 精选
- 马儿总结一下: 1. Listener初始化的时候将交给Ioc管理的Bean初始化 2.Servlet初始化的时候将controller相关的bean初始化 这两步初始化将bean的管理从DispatcherServlet剥离交给了第一章创建的Ioc容器 3.将具体的url和对象+方法的管理从Servlet交给HandlerMapping来处理 4.将具体的方法执行剥离到HandlerAdapter 这两步将DispatcherServlet变得更抽象了,利用serviece方法可以同时处理不同类型的请求 一点建议: 1. DispatcherServlet中的controller相关bean的初始化已经交给AnnotationConfigWebApplicationContext管理了,它的init方法不用在调用initController了
作者回复: 赞你一个
2023-04-01归属地:四川8 - lmnsds在github代码的geek_mvc3分支找了半天 这节课的 DispatcherServlet,原来不是在web包下改的原有类,而是在web.servlet包下新增了个DispatcherServlet!浪费了好多时间!给后来人提个醒吧。
作者回复: 多谢提醒
2023-05-15归属地:北京2 - 风轻扬思考题:我的想法是模仿SpringMVC,在RequestMapping注解上增加一个HttpMethod的属性(当前方法允许的请求方式)。在解析RequestMapping注解的时候改动一下,拿到RequestMapping注解上的HttpMethod,将其放到HandlerMethod中,然后将HandlerMathod对象放进MappingRegistry的一个map中,key:path,value:HandlerMethod。用户发起请求时,doDispatch方法中,获取到HttpServletRequest对象中的请求方式和MappingRegistry中存储的HandlerMethod上的请求方式进行比较,如果符合就可以访问,否则就报出方法类型不匹配 另外,有两个问题请教一下老师。 1、问题一: DefaultListableBeanFactory beanFactory; DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); this.beanFactory = bf; 我看老师在很多地方都是这样写的,为啥不直接给成员变量赋值呢?this.beanFactory = = new DefaultListableBeanFactory(); 2、问题2 为什么Spring要搞出两个容器来呢? 我从StackOverFLow上搜了一下相关解释:https://stackoverflow.com/questions/18578143/about-multiple-containers-in-spring-framework 看上面的解释是: 这样分开更清晰,Dispatcher驱动的子容器专门用来处理controller组件,ContextLoaderListener驱动的父容器专门用来处理业务逻辑组件以及持久化组件。 除了这个原因,Spring搞2个容器还有其他原因吗?
作者回复: 思考题后面有再回首章节里面给出了参考,你可以到时候再思考一下。 Q1,习惯问题吧,Spring框架本身也是经常这样写。有一个潜在原因,但是我不是很确定,就是方法中尽量使用local变量,只在尽量少的场合使用实例变量和方法参数,这样提高性能减少开销。编译器优化是这么说的,但是我也不确定一定就是这样。另外,对源码,我还是建议最后去读Spring框架的源代码,那是世界顶级程序员的力作(推广到别的也是一样的,Apache Tomcat,JDK,Apache Dubbo)。我自己也是在跟着他们的时候一旁偷学了几招,MiniSpring的目的是剖析Spring框架内部结构,作为一个简明地图引导大家理解Spring。 Q2,就是这样解释的。Spring体系中IoC是核心层,MVC只是外周的部分,理论上是可以不启用的可选部件。软件是一层层堆积的,层次感要慢慢培养。
2023-04-08归属地:北京22 - 赵欣有几个文件跟原来版本相比也有些变化了,大家注意下,一个是AbstractBeanFactory.java一个是DefaultListableBeanFactory.java文件。
作者回复: 赞你
2024-03-15归属地:广东 - 睿智的仓鼠不可多得的好课,跟到现在学到很多
作者回复: 感谢!
2023-06-07归属地:湖北 - 梦某人首先以个人理解回答课后题,目前的请求并不分 get 或者 post,主要是以请求的路径进行区分,如果想要处理 post 请求, 需要构建新的 HandlerAdapter,对 Request 中的 post body 内容进行额外的解析和处理,然后操作方法。当然可能还需要构建 HandlerMapping 来处理请求路径,但是个人没想到什么 get 和 post 区别很大的地方。 第二和第三点是个人跟写的时候遇到的一些问题,给其他同学一点参考。 第二个, ``` // getBeanDefinitionNames 方法中 return (String[]) this.beanNames.toArray(); //替换成 return this.beanNames.toArray(new String[0]); ``` 可以减少一些类型转换异常,特别是当 ArrayList 里面只有一个 String 元素的时候。 第三个,BeanDefinition 中的部分 get 方法应该增加运算符 防止返回 Null 而不是 empty,导致空指针异常。例如: ``` public ArgumentValues getArgumentValues() { return argumentValues == null? new ArgumentValues(): argumentValues; } ``` 第四点是课程个人理解了:两级的 WebApplicationContext 第一级在 Listener 的时候加载,加载了 beans.xml (或者 Application.xml ) 中的 bean, 然后作为 第二级 AnnotationConfigWebApplicationContext 的父级, 第二级别通过 mvc.xml 提供的扫包路径进行扫包加载 bean,同时注册带有注解的方法。 当路由请求来的时候,先从第二级的 WebApplicationContext 获取 bean 和其方法进行处理,所以这个两级在最后的时候以 Controller 和 Service 来进行讲解,不是真的 Controller 和 Service, 而是说 第二级处理事物的触发逻辑比第一级更早,加载的逻辑则比他更晚,就好像 请求先到 Controller 后到 Service 一样。 最后的最后,,,看着老师文稿给的代码来吵,已经是和 GitHub 中的代码差别越来越大了, Debug 起来更加费时,但是好处是理解加深了。
作者回复: 写得很好很好。我觉得,不管通过什么方式,最后能达到理解了Spring框架的目的就好了,我的建议还是读文稿,听我讲,手工练习,自己动手过一遍就是不一样的,线下班学员还要做扩展练习,加上更多功能和鲁棒性。源代码方面,MiniSpring主要是便于教学时理解Spring框架的结构,代码最后要学习Spring框架本身的源代码。
2023-04-05归属地:河北 - C.出去玩了两天,今天把这章也结束掉了。代码运行一切正常。
作者回复: 赞
2023-04-03归属地:江苏 - Geek_3207301. 课后题:重写service后不是Get 和Post都能处理吗? 2.扫描的包里有接口,接口应该是不能实例化的,我过滤了下接口类型才能启动起来,对比了下老师的代码,好像并没有处理。 3.尝试了下在HelloWorldBean里注入parentApplicationContext中创建的Bean,发现了个小问题,AbstractBeanFactory#getBean方法中如果获取不到BeanDefinition 应该返回个null,而不是抛出异常,否则不会去父类查找。对构造器注入参数和set注入参数增加null校验
作者回复: 你的思考和练习很好有深度,用心了。MiniSpring是为了学习构建的,不是工业级的。线下听课的几波学生,要对照代码进行扩展练习,自己增加功能特性增加鲁棒性。
2023-04-02归属地:北京2 - peter请教两个问题: DispatcherServlet 这个类里,有两个WebApplicationContext对象:private WebApplicationContext webApplicationContext; private WebApplicationContext parentApplicationContext; 请问,这两个对象是同一个对象吗?? Q2:文中的controller和service是业务层的吗? 文中有这样的描述:“按照通行的 Web 分层体系,一个程序它在结构上会有 Controller 和 Service 两层。在我们的程序中,Controller 由 DispatcherServlet 负责启动,Service 由 Listener 负责启动。” 程序员写业务代码的时候,会按照controller、service、dao来写。 请问,文中的controller和service是业务层的controller、service吗?(即程序员写的controller、service)
作者回复: 不是同一个,是两级context. controller和service是两层,并不特别规定是谁。我这里主要想描述的是dispatcherservlet中的控制逻辑与ioc容器中管理的bean的业务逻辑是前后两层的关系。
2023-04-01归属地:北京2 - Geek_149cde不明白 AnnotationConfigWebApplicationContext 文件里 loadBeanDefinitions 加载的时候不应该把 AService 接口也加载进去了吗?创建 Bean 的时候不是就报错了2023-07-03归属地:山西