整合IoC和MVC在Web环境中启动IoC容器 -- 知识铺
aaaaaaa a# 整合IoC和MVC:在Web环境中启动IoC容器
你好,我是郭屹。
通过上一节课的工作,我们已经初步实现了一个基础的MVC框架,并且引入了@RequestMapping
注解以及对指定包进行全局扫描来简化XML配置。然而,这个MVC框架是独立运行的,并没有与之前创建的IoC(控制反转)容器整合在一起。
在这节课中,我们将把IoC容器与MVC框架结合,使MVC中的Controller能够引用IoC容器中的Bean,从而形成一个统一的整体。
Servlet服务器启动过程
IoC容器是自包含的服务,而MVC框架则需要遵守Web标准。为了将这两者结合起来,我们需要了解一些关于Web规范的知识。根据Servlet规范,当服务器启动时,它会依据web.xml
文件来进行配置。
web.xml配置文件概述
- web.xml 文件是Java Servlet规范定义的一个配置文件,它包含了Web应用的所有配置信息。
- 每个Java Web应用都必须有一个位于
WEB-INF
目录下的web.xml
文件。 web.xml
的根元素是<web-app>
,并且指定了命名空间和schema。- 常见的配置项包括:
- context-param:用于设置上下文参数。
- Listener:监听器,可以用来监听Web应用的各种事件。
- Filter:过滤器,可以在请求到达Servlet之前或响应返回客户端之前处理请求或响应。
- Servlet:声明Servlet及其映射路径。 理解这些配置对于我们在Web环境下正确地启动IoC容器至关重要。接下来,我们将探讨如何具体实施这一整合。
|
|
当Servlet服务器如Tomcat启动的时候,要遵守下面的时序:
- 在启动Web项目时,Tomcat会读取web.xml中的context-param节点,获取这个Web应用的全局参数。
- Tomcat创建一个ServletContext实例,是全局有效的。
- 将context-param的参数转换为键值对,存储在ServletContext里。
- 创建listener中定义的监听类的实例,按照规定Listener要继承自ServletContextListener。监听器初始化方法是contextInitialized(ServletContextEvent event)。初始化方法中可以通过event.getServletContext().getInitParameter(“name”)方法获得上下文环境中的键值对。
- 当Tomcat完成启动,也就是contextInitialized方法完成后,再对Filter过滤器进行初始化。
- servlet初始化:有一个参数load-on-startup,它为正数的值越小优先级越高,会自动启动,如果为负数或未指定这个参数,会在servlet被调用时再进行初始化。init-param 是一个servlet整个范围之内有效的参数,在servlet类的init()方法中通过 this.getInitParameter(“param1”)方法获得。 规范中规定的这个时序,就是我们整合两者的关键所在。
Listener初始化启动IoC容器
由上述服务器启动过程我们知道,我们把web.xml文件里定义的元素加载过程简单归总一下:先获取全局的参数context-param来创建上下文,之后如果配置文件里定义了Listener,那服务器会先启动它们,之后是Filter,最后是Servlet。因此我们可以利用这个时序,把容器的启动放到Web应用的Listener中。 Spring MVC就是这么设计的,它按照这个规范,用ContextLoaderListener来启动容器。我们也模仿它同样来实现这样一个Listener。
|
|
ContextLoaderListener类中声明了一个常量CONFIG_LOCATION_PARAM,其默认值为contextConfigLocation。这个常量代表配置文件路径,即IoC容器的配置文件路径。因此,Listener期望在web.xml文件中有一个参数用于指定配置文件路径。我们可以查看web.xml文件以了解具体配置。
|
|
Listener 类的定义
在上述文件中定义了一个 Listener 类,该类负责加载全局参数并指定配置文件的路径。
ContextLoaderListener 类的作用
ContextLoaderListener
类中定义了 WebApplicationContext
对象,虽然目前该对象还不存在,但通过其名称我们可以推断出 WebApplicationContext
是一个上下文接口,主要用于 Web 项目中。
定义 WebApplicationContext
为了定义 WebApplicationContext
,我们需要了解其在 Web 项目中的作用和实现方式。以下是定义 WebApplicationContext
的步骤和要点:
-
理解上下文接口:
WebApplicationContext
是 Spring 框架中用于管理 Web 应用程序上下文的接口。 -
配置文件加载:
ContextLoaderListener
通过监听特定的事件来加载配置文件,为应用程序提供必要的上下文信息。 -
上下文初始化:在 Web 应用程序启动时,
ContextLoaderListener
会初始化WebApplicationContext
,确保所有的 Bean 都被正确加载和配置。 -
上下文使用:在应用程序运行过程中,
WebApplicationContext
提供了访问和管理应用程序上下文的接口,包括 Bean 的查找和事件的发布等。
结论
通过上述步骤,我们可以定义 WebApplicationContext
并利用 ContextLoaderListener
在 Web 项目中管理和维护应用程序的上下文环境。
|
|
ServletContext与ContextLoaderListener
在Web应用开发中,ServletContext
是Servlet容器提供的用于存储全局信息的接口。ContextLoaderListener
是一个特殊的监听器,用于在Web应用启动时初始化Spring的WebApplicationContext
,并将其存储在ServletContext
的属性中,以便在整个应用中共享和访问。
1. ServletContext的作用
ServletContext提供了一种方式,允许各个Servlet之间共享信息。它是一个域对象,可以存储属性,这些属性在整个Web应用的生命周期内都是可访问的。
2. ContextLoaderListener的职责
ContextLoaderListener
的主要任务是在Web应用启动时加载Spring的WebApplicationContext
。这个上下文包含了应用的所有Spring管理的Bean,是Spring应用的核心。
3. 初始化WebApplicationContext
在ContextLoaderListener
的contextInitialized
方法中,我们初始化WebApplicationContext
。这个过程通常涉及到加载Spring的配置文件,并创建应用上下文。
4. 存储WebApplicationContext
一旦WebApplicationContext
被创建,我们需要将其存储在ServletContext
的属性中。这样,其他组件就可以通过ServletContext
获取到这个上下文,进而访问Spring管理的Bean。
5. 使用ServletContext的Attribute存储上下文
我们将WebApplicationContext
存储在ServletContext
的属性中,通常使用一个特定的属性名,如' '
,来标识这个上下文。这样,任何需要访问Spring上下文的Servlet或Listener都可以通过这个属性名来获取上下文。
|
|
在Java Web应用中,通过web.xml配置文件获取到如applicationContext.xml
这样的配置文件路径。接着,利用该路径创建一个AnnotationConfigWebApplicationContext
对象,我们称之为WAC。这个WAC就是新的Spring应用上下文。
随后,通过调用servletContext.setAttribute()
方法,并按照默认的属性值,将WAC设置到servletContext
中。这样一来,AnnotationConfigWebApplicationContext
与servletContext
之间就可以互相引用,这为程序内部组件之间的交互提供了便利。
AnnotationConfigWebApplicationContext
是Spring框架中的一个类,它继承自GenericApplicationContext
并实现了ConfigurableApplicationContext
接口。此类主要用于支持基于注解的配置,允许开发者使用纯Java代码来定义和配置Spring容器中的Bean,而无需XML配置文件。这种方式不仅简化了配置过程,也使得应用程序更加易于维护。
|
|
AnnotationConfigWebApplicationContext 与 IoC 容器的关系
AnnotationConfigWebApplicationContext 类继承自 IoC 容器中的 ClassPathXmlApplicationContext,它在 ClassPathXmlApplicationContext 的基础上增加了对 servletContext 的支持,使其适用于 Web 应用场景。
配置文件 applicationContext.xml
在 Web 应用中,我们使用 applicationContext.xml 作为配置文件,该文件由 web.xml 中定义的一个参数指定。
配置文件的作用
-
applicationContext.xml 文件用于定义 Spring 框架中的 Bean 和相关的配置。
-
它允许开发者通过 XML 格式定义应用的配置信息,包括但不限于 Bean 的定义、属性注入、以及 Bean 之间的依赖关系。
在 web.xml 中的配置
-
在 web.xml 文件中,我们通过指定参数来引入 applicationContext.xml 文件,从而将 Spring 的配置集成到 Web 应用中。
-
这允许 Web 应用利用 Spring 框架提供的 IoC 容器功能,实现依赖注入和 Bean 管理。
|
|
这个配置文件就是我们现在的IoC容器的配置文件,主要作用是声明Bean,如:
|
|
回顾一下,现在完整的过程是:当Servlet服务器启动时,Listener会优先启动,读配置文件路径,启动过程中初始化上下文,然后启动IoC容器,这个容器通过refresh()方法加载所管理的Bean对象。这样就实现了Tomcat启动的时候同时启动IoC容器。
好了,到了这一步,IoC容器启动了,我们回来再讨论MVC这边的事情。我们已经知道,在服务器启动的过程中,会注册Web应用上下文,也就是WAC。这样方便我们通过属性拿到启动时的WebApplicationContext。
|
|
因此我们改造一下DispatcherServlet这个核心类里的init()方法。
|
|
Servlet初始化过程
1. 获取WebApplicationContext
在Servlet初始化阶段,首先从ServletContext
中获取属性,以获得Listener在启动时注册的WebApplicationContext
。
2. 获取配置文件路径
接着,获取Servlet配置参数contextConfigLocation
,该参数表示配置文件的路径,通常指向MVC使用的配置文件,例如minisMVC-servlet.xml
。
3. 扫描包和加载Bean
在获取到配置文件路径后,扫描指定路径下的包,并调用refresh()
方法来加载Bean,完成DispatcherServlet的初始化。
构建URL与后端程序映射关系
1. 改造initMapping()方法
按照新的方法构建URL和后端程序之间的映射关系,需要查找所有使用了@RequestMapping
注解的方法。
2. 存储URL和映射信息
将URL存放到urlMappingNames
中,映射的对象存放到mappingObjs
中,映射的方法存放到mappingMethods
中。这种方法替代了过去通过解析Bean得到的映射关系,减少了XML文件中的手工配置。
3. 查看相关代码
可以通过查看相关代码来进一步了解这一过程的具体实现。
|
|
最后稍微调整一下 doGet() 方法内的代码,去除不再使用的结构。
|
|
整合了IoC容器的MVC实现
在我们的Web应用中,doGet()
方法承担着处理HTTP GET请求的任务。它会从请求中解析出访问路径,并根据这个路径与后端程序之间的映射关系来决定调用哪个对象的哪个方法。执行完相应的方法之后,将结果直接返回给客户端。
doGet() 方法详解
- 获取访问路径:首先,
doGet()
方法会读取请求中的URL路径部分。 - 映射到后端逻辑:然后,通过预定义好的映射规则(通常是配置文件或注解的形式),确定要调用的具体服务类和服务方法。
- 调用对应方法:接着,使用IoC容器管理的服务实例来调用对应的方法。
- 返回结果:最后,将方法执行的结果包装成合适的格式并通过
response
对象发送回客户端。
完整流程示例
假设有一个简单的用户信息查询接口,其URL为/user/info
,则整个处理过程可能如下:
doGet()
接收到请求并识别出请求路径是/user/info
。2. 根据映射规则,找到应该调用UserService
类下的getUserInfo()
方法。3. IoC容器提供UserService
的一个实例。4. 调用getUserInfo()
方法获取用户信息。5. 将得到的信息转换成JSON字符串形式。6. 设置响应头信息,并将JSON字符串写入response
对象,从而完成响应。
验证
为了确保上述功能正确无误地工作,接下来我们将查看Tomcat服务器使用的web.xml
配置文件以确认相关设置是否恰当。
|
|
然后是IoC容器使用的配置文件applicationContext.xml。
|
|
MVC扫描的配置文件minisMVC-servlet.xml。
|
|
最后,在com.minis.test.HelloworldBean内的测试方法上,增加@RequestMapping注解。
|
|
Tomcat测试与MVC和IoC整合
在本节课中,我们成功地将MVC设计模式与IoC(控制反转)容器进行了整合,并通过Tomcat服务器启动了我们的应用程序。当你在浏览器中输入 localhost:8080/test
并看到预期的结果时,这标志着我们的配置是正确的。这个端口号可以根据需要自定义,同时请求路径可能还需要根据实际的应用上下文进行调整。
整合过程详解
-
Tomcat启动阶段:
-
首先读取
context-param
参数。 -
初始化监听器(Listener),在这个过程中会创建IoC容器并构建WebApplicationContext (WAC)。
-
WAC加载被管理的Bean对象,并将其关联到servlet context中。
-
DispatcherServlet初始化:
-
从servletContext获取属性以获得WAC,并将其设置为servlet的属性之一。
-
根据servlet的配置读取路径参数。
-
扫描指定路径下的包来发现组件。
-
调用
refresh()
方法加载更多Bean。 -
最后配置URL映射关系。
关键点理解
能够实现MVC与IoC的整合,关键在于遵循了Servlet规范所规定的生命周期顺序:从监听器、过滤器到最后的servlet。这种顺序为我们提供了干预程序执行流程的机会,使得我们可以插入自己的逻辑代码。 在开发软件时,重要的是学习如何建立一个可扩展的系统结构。这意味着不应该把程序的流程固定得太死板,而应该留有足够的接口和扩展点,让其他开发者也能方便地加入他们自己的业务逻辑。 框架之所以成为框架而不是单纯的应用程序,正是因为它提供了一套高度可扩展的体系结构,给后续的程序员留下了极大的发展空间。阅读如Rodd Johnson等大师级人物编写的源代码,就像是品鉴一部文学杰作,让人不禁感叹其优雅的设计。
完整源码
如果你想查看完整的源代码示例,可以访问 https://github.com/YaleGuo/minis。
课后思考题
既然我们知道可以通过DispatcherServlet访问WebApplicationContext中管理的Bean,那么反过来是否可以通过WebApplicationContext访问到由DispatcherServlet管理的Bean呢?欢迎你在讨论区分享你的想法。如果你觉得这节课对你有所帮助,请不要犹豫把它推荐给你认为需要的朋友。期待下次课程与你再次相见!aaaaaa
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek002/post/202410/%E6%95%B4%E5%90%88IoC%E5%92%8CMVC%E5%9C%A8Web%E7%8E%AF%E5%A2%83%E4%B8%AD%E5%90%AF%E5%8A%A8IoC%E5%AE%B9%E5%99%A8--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com