当前位置: 代码迷 >> Web前端 >> IoC器皿在Web容器中的启动
  详细解决方案

IoC器皿在Web容器中的启动

热度:266   发布时间:2012-10-08 19:54:56.0
IoC容器在Web容器中的启动

以下引用自博客:http://jiwenke-spring.blogspot.com/
上面我们分析了IOC容器本身的实现,下面我们看看在典型的web环境中,Spring IOC容器是怎样被载入和起作用的。
简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文的扩展接口
WebApplicationContext:

Java代码
1.public interface WebApplicationContext extends ApplicationContext {??
2.??? //这里定义的常量用于在ServletContext中存取根上下文??
3.??? String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";??
4.??? ......??
5.??? //对WebApplicationContext来说,需要得到Web容器的ServletContext??
6.??? ServletContext getServletContext();??
7.}?
public interface WebApplicationContext extends ApplicationContext {
??? //这里定义的常量用于在ServletContext中存取根上下文
??? String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
??? ......
??? //对WebApplicationContext来说,需要得到Web容器的ServletContext
??? ServletContext getServletContext();
}

而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext - 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。

Java代码
1.public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {??
2.?
3.??? /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/?
4.??? public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";??
5.??? public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";??
6.??? public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";??
7.?????
8.??? //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。??
9.??? protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {??
10.??????? //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析??
11.??????? XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);??
12.?
13.??????? beanDefinitionReader.setResourceLoader(this);??
14.??????? beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));??
15.?
16.??????? initBeanDefinitionReader(beanDefinitionReader);??
17.??????? loadBeanDefinitions(beanDefinitionReader);??
18.??? }??
19.?
20.??? protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {??
21.??? }??
22.??? //使用XmlBeanDefinitionReader来读入bean定义信息??
23.??? protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {??
24.??????? String[] configLocations = getConfigLocations();??
25.??????? if (configLocations != null) {??
26.??????????? for (int i = 0; i < configLocations.length; i++) {??
27.??????????????? reader.loadBeanDefinitions(configLocations[i]);??
28.??????????? }??
29.??????? }??
30.??? }??
31.??? //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml??
32.??? protected String[] getDefaultConfigLocations() {??
33.??????? if (getNamespace() != null) {??
34.??????????? return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};??
35.??????? }??
36.??????? else {??
37.??????????? return new String[] {DEFAULT_CONFIG_LOCATION};??
38.??????? }??
39.??? }??
40.}?
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {

??? /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/
??? public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
??? public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
??? public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
??
??? //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。
??? protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
??????? //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析
??????? XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

??????? beanDefinitionReader.setResourceLoader(this);
??????? beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

??????? initBeanDefinitionReader(beanDefinitionReader);
??????? loadBeanDefinitions(beanDefinitionReader);
??? }

??? protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
??? }
??? //使用XmlBeanDefinitionReader来读入bean定义信息
??? protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
??????? String[] configLocations = getConfigLocations();
??????? if (configLocations != null) {
??????????? for (int i = 0; i < configLocations.length; i++) {
??????????????? reader.loadBeanDefinitions(configLocations[i]);
??????????? }
??????? }
??? }
??? //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml
??? protected String[] getDefaultConfigLocations() {
??????? if (getNamespace() != null) {
??????????? return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
??????? }
??????? else {
??????????? return new String[] {DEFAULT_CONFIG_LOCATION};
??????? }
??? }
}

对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext),Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 - 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。
下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:

Java代码
1.WebApplicationContext getWebApplicationContext(ServletContext sc)?
??? WebApplicationContext getWebApplicationContext(ServletContext sc)

以Tomcat作为Servlet容器为例,下面是具体的步骤:
1.Tomcat 启动时需要从web.xml中读取启动参数,在web.xml中我们需要对ContextLoaderListener进行配置,对于在web应用启动入口是在ContextLoaderListener中的初始化部分;从Spring MVC上看,实际上在web容器中维护了一系列的IOC容器,其中在ContextLoader中载入的IOC容器作为根上下文而存在于 ServletContext中。

Java代码
1.//这里对根上下文进行初始化。??
2.public void contextInitialized(ServletContextEvent event) {??
3.??? //这里创建需要的ContextLoader??
4.??? this.contextLoader = createContextLoader();??
5.??? //这里使用ContextLoader对根上下文进行载入和初始化??
6.??? this.contextLoader.initWebApplicationContext(event.getServletContext());??
7.}?
??? //这里对根上下文进行初始化。
??? public void contextInitialized(ServletContextEvent event) {
??????? //这里创建需要的ContextLoader
??????? this.contextLoader = createContextLoader();
??????? //这里使用ContextLoader对根上下文进行载入和初始化
??????? this.contextLoader.initWebApplicationContext(event.getServletContext());
??? }

通过ContextLoader建立起根上下文的过程,我们可以在ContextLoader中看到:

Java代码
1.public WebApplicationContext initWebApplicationContext(ServletContext servletContext)??
2.??????? throws IllegalStateException, BeansException {??
3.??? //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。??
4.??? if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {??
5.??? //直接抛出异常??
6.??? .........??
7.??? }??
8.????
9.??? ...............??
10.??? try {??
11.??????? // 这里载入根上下文的父上下文??
12.??????? ApplicationContext parent = loadParentContext(servletContext);??
13.?
14.??????? //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是??
15.??????? //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文??
16.??????? this.context = createWebApplicationContext(servletContext, parent);??
17.??????? servletContext.setAttribute(??
18.??????????????? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);??
19.??????? ..........??
20.?
21.??????? return this.context;??
22.??? }??
23.?????? ............??
24.}?
??? public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
??????????? throws IllegalStateException, BeansException {
??????? //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。
??????? if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
??????? //直接抛出异常
??????? .........
??????? }
?????
??????? ...............
??????? try {
??????????? // 这里载入根上下文的父上下文
??????????? ApplicationContext parent = loadParentContext(servletContext);

??????????? //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是
??????????? //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文
??????????? this.context = createWebApplicationContext(servletContext, parent);
??????????? servletContext.setAttribute(
??????????????????? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
??????????? ..........

??????????? return this.context;
??????? }
?????????? ............
??? }

建立根上下文的父上下文使用的是下面的代码,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数:

Java代码
1.protected ApplicationContext loadParentContext(ServletContext servletContext)??
2.??????? throws BeansException {??
3.?
4.??? ApplicationContext parentContext = null;??
5.?
6.??? String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);??
7.??? String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);??
8.?
9.??? if (locatorFactorySelector != null) {??
10.??????? BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);??
11.??????? ........??
12.??????? //得到根上下文的父上下文的引用??
13.??????? this.parentContextRef = locator.useBeanFactory(parentContextKey);??
14.??????? //这里建立得到根上下文的父上下文??
15.??????? parentContext = (ApplicationContext) this.parentContextRef.getFactory();??
16.??? }??
17.?
18.??? return parentContext;??
19.}?
??? protected ApplicationContext loadParentContext(ServletContext servletContext)
??????????? throws BeansException {

??????? ApplicationContext parentContext = null;

??????? String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
??????? String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);

??????? if (locatorFactorySelector != null) {
??????????? BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
??????????? ........
??????????? //得到根上下文的父上下文的引用
??????????? this.parentContextRef = locator.useBeanFactory(parentContextKey);
??????????? //这里建立得到根上下文的父上下文
??????????? parentContext = (ApplicationContext) this.parentContextRef.getFactory();
??????? }

??????? return parentContext;
??? }

得到根上下文的父上下文以后,就是根上下文的创建过程:

Java代码
1.protected WebApplicationContext createWebApplicationContext(??
2.??????? ServletContext servletContext, ApplicationContext parent) throws BeansException {??
3.??? //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,??
4.??? //如果没有使用默认的。??
5.??? Class contextClass = determineContextClass(servletContext);??
6.??? .........??
7.??? //这里就是上下文的创建过程??
8.??? ConfigurableWebApplicationContext wac =??
9.??????????? (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);??
10.??? //这里保持对父上下文和ServletContext的引用到根上下文中??
11.??? wac.setParent(parent);??
12.??? wac.setServletContext(servletContext);??
13.?
14.??? //这里从web.xml中取得相关的初始化参数??
15.??? String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);??
16.??? if (configLocation != null) {??
17.??????? wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,??
18.??????????????? ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));??
19.??? }??
20.?? //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。??
21.??? wac.refresh();??
22.??? return wac;??
23.}?
??? protected WebApplicationContext createWebApplicationContext(
??????????? ServletContext servletContext, ApplicationContext parent) throws BeansException {
??????? //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,
??????? //如果没有使用默认的。
??????? Class contextClass = determineContextClass(servletContext);
??????? .........
??????? //这里就是上下文的创建过程
??????? ConfigurableWebApplicationContext wac =
??????????????? (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
??????? //这里保持对父上下文和ServletContext的引用到根上下文中
??????? wac.setParent(parent);
??????? wac.setServletContext(servletContext);

??????? //这里从web.xml中取得相关的初始化参数
??????? String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
??????? if (configLocation != null) {
??????????? wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
??????????????????? ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
??????? }
?????? //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。
??????? wac.refresh();
??????? return wac;
??? }

初始化根ApplicationContext后将其存储到SevletContext中去以后,这样就建立了一个全局的关于整个应用的上下文。这个根上下文会被以后的DispatcherServlet初始化自己的时候作为自己ApplicationContext的父上下文。这个在对 DispatcherServlet做分析的时候我们可以看看到。

3.完成对ContextLoaderListener的初始化以后, Tomcat开始初始化DispatchServlet,- 还记得我们在web.xml中队载入次序进行了定义。DispatcherServlet会建立自己的ApplicationContext,同时建立这个自己的上下文的时候会从ServletContext中得到根上下文作为父上下文,然后再对自己的上下文进行初始化,并最后存到 ServletContext中去供以后检索和使用。
可以从DispatchServlet的父类FrameworkServlet的代码中看到大致的初始化过程,整个ApplicationContext的创建过程和ContextLoder创建的过程相类似:

Java代码
1.protected final void initServletBean() throws ServletException, BeansException {??
2.??? .........??
3.??? try {??
4.??????? //这里是对上下文的初始化过程。??
5.??????? this.webApplicationContext = initWebApplicationContext();??
6.??????? //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素??
7.??????? initFrameworkServlet();??
8.??? }??
9.?? ........??
10.}?
??? protected final void initServletBean() throws ServletException, BeansException {
??????? .........
??????? try {
??????????? //这里是对上下文的初始化过程。
??????????? this.webApplicationContext = initWebApplicationContext();
??????????? //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素
??????????? initFrameworkServlet();
??????? }
?????? ........
??? }

对initWebApplicationContext()调用的代码如下:

Java代码
1.protected WebApplicationContext initWebApplicationContext() throws BeansException {??
2.??? //这里调用WebApplicationContextUtils静态类来得到根上下文??
3.??? WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());??
4.?????
5.??? //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;??
6.??? WebApplicationContext wac = createWebApplicationContext(parent);??
7.??? ........??
8.??? if (isPublishContext()) {??
9.??????? //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。??
10.??????? String attrName = getServletContextAttributeName();??
11.??????? getServletContext().setAttribute(attrName, wac);??
12.??? }??
13.??? return wac;??
14.}?
??? protected WebApplicationContext initWebApplicationContext() throws BeansException {
??????? //这里调用WebApplicationContextUtils静态类来得到根上下文
??????? WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
??????
??????? //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
??????? WebApplicationContext wac = createWebApplicationContext(parent);
??????? ........
??????? if (isPublishContext()) {
??????????? //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。
??????????? String attrName = getServletContextAttributeName();
??????????? getServletContext().setAttribute(attrName, wac);
??????? }
??????? return wac;
??? }

其中我们看到调用了WebApplicationContextUtils的静态方法得到根ApplicationContext:

Java代码
1.??? public static WebApplicationContext getWebApplicationContext(ServletContext sc) {??
2.??????? //很简单,直接从ServletContext中通过属性名得到根上下文??
3.??????? Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);??
4.??????? .......??
5.??????? return (WebApplicationContext) attr;??
6.??? }??
7.然后创建DispatcherServlet自己的WebApplicationContext:??
8.??? protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)??
9.??????????? throws BeansException {??
10.??????? .......??
11.??????? //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =?????????????????????????????
12.??????? //XmlWebApplicationContext.class;??
13.??????? ConfigurableWebApplicationContext wac =??
14.??????????????? (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());??
15.?
16.??????? //这里配置父上下文,就是在ContextLoader中建立的根上下文??
17.??????? wac.setParent(parent);??
18.?
19.??????? //保留ServletContext的引用和相关的配置信息。??
20.??????? wac.setServletContext(getServletContext());??
21.??????? wac.setServletConfig(getServletConfig());??
22.??????? wac.setNamespace(getNamespace());??
23.?
24.??????? //这里得到ApplicationContext配置文件的位置??
25.??????? if (getContextConfigLocation() != null) {??
26.??????????? wac.setConfigLocations(??
27.??????????????? StringUtils.tokenizeToStringArray(??
28.??????????????????????????? getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));??
29.??????? }??
30.?????????
31.??????? //这里调用ApplicationContext的初始化过程,同样需要使用refresh()??
32.??????? wac.refresh();??
33.??????? return wac;??
34.??? }?
??? public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
??????? //很简单,直接从ServletContext中通过属性名得到根上下文
??????? Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
??????? .......
??????? return (WebApplicationContext) attr;
??? }
然后创建DispatcherServlet自己的WebApplicationContext:
??? protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
??????????? throws BeansException {
??????? .......
??????? //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =??????????????????????????
??????? //XmlWebApplicationContext.class;
??????? ConfigurableWebApplicationContext wac =
??????????????? (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());

??????? //这里配置父上下文,就是在ContextLoader中建立的根上下文
??????? wac.setParent(parent);

??????? //保留ServletContext的引用和相关的配置信息。
??????? wac.setServletContext(getServletContext());
??????? wac.setServletConfig(getServletConfig());
??????? wac.setNamespace(getNamespace());

??????? //这里得到ApplicationContext配置文件的位置
??????? if (getContextConfigLocation() != null) {
??????????? wac.setConfigLocations(
??????????????? StringUtils.tokenizeToStringArray(
??????????????????????????? getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
??????? }
??????
??????? //这里调用ApplicationContext的初始化过程,同样需要使用refresh()
??????? wac.refresh();
??????? return wac;
??? }

4. 然后就是DispatchServlet中对Spring MVC的配置过程,首先对配置文件中的定义元素进行配置 - 请注意这个时候我们的WebApplicationContext已经建立起来了,也意味着DispatcherServlet有自己的定义资源,可以需要从web.xml中读取bean的配置信息,通常我们会使用单独的xml文件来配置MVC中各个要素定义,这里和web容器相关的加载过程实际上已经完成了,下面的处理和普通的Spring应用程序的编写没有什么太大的差别,我们先看看MVC的初始化过程:

Java代码
1.protected void initFrameworkServlet() throws ServletException, BeansException {??
2.??? initMultipartResolver();??
3.??? initLocaleResolver();??
4.??? initThemeResolver();??
5.??? initHandlerMappings();??
6.??? initHandlerAdapters();??
7.??? initHandlerExceptionResolvers();??
8.??? initRequestToViewNameTranslator();??
9.??? initViewResolvers();??
10.}?
??? protected void initFrameworkServlet() throws ServletException, BeansException {
??????? initMultipartResolver();
??????? initLocaleResolver();
??????? initThemeResolver();
??????? initHandlerMappings();
??????? initHandlerAdapters();
??????? initHandlerExceptionResolvers();
??????? initRequestToViewNameTranslator();
??????? initViewResolvers();
??? }

5. 这样MVC的框架就建立起来了,DispatchServlet对接受到的HTTP Request进行分发处理由doService()完成,具体的MVC处理过程我们在doDispatch()中完成,其中包括使用Command模式建立执行链,显示模型数据等,这些处理我们都可以在DispatcherServlet的代码中看到:

Java代码
1.protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {??
2.??? ......??
3.??? try {??
4.??????? doDispatch(request, response);??
5.??? }??
6.?? .......??
7.}?
??? protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
??????? ......
??????? try {
??????????? doDispatch(request, response);
??????? }
?????? .......
??? }

实际的请求分发由doDispatch(request,response)来完成:

Java代码
1.protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {??
2.???? .......??
3.???? // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。??
4.???? HandlerExecutionChain mappedHandler = null;??
5.?????
6.????? ......??
7.????? try {??
8.????????? //我们熟悉的ModelAndView在这里出现了。??
9.????????? ModelAndView mv = null;??
10.????????? try {??
11.????????????? processedRequest = checkMultipart(request);??
12.?
13.????????????? //这里更具request中的参数和映射关系定义决定使用的handler??
14.????????????? mappedHandler = getHandler(processedRequest, false);??
15.?
16.????????????? ......??
17.????????????? //这里是handler的调用过程,类似于Command模式中的execute.??
18.????????????? HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());??
19.????????????? mv = ha.handle(processedRequest, response, mappedHandler.getHandler());??
20.?
21.????????????? .......??
22.????????? //这里将模型数据通过视图进行展现??
23.????????? if (mv != null && !mv.wasCleared()) {??
24.????????????? render(mv, processedRequest, response);??
25.????????? }??
26.??????????? ........??
27.? }?
? protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {
?????? .......
?????? // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。
?????? HandlerExecutionChain mappedHandler = null;
????
??????? ......
??????? try {
??????????? //我们熟悉的ModelAndView在这里出现了。
??????????? ModelAndView mv = null;
??????????? try {
??????????????? processedRequest = checkMultipart(request);

??????????????? //这里更具request中的参数和映射关系定义决定使用的handler
??????????????? mappedHandler = getHandler(processedRequest, false);

??????????????? ......
??????????????? //这里是handler的调用过程,类似于Command模式中的execute.
??????????????? HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
??????????????? mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

??????????????? .......
??????????? //这里将模型数据通过视图进行展现
??????????? if (mv != null && !mv.wasCleared()) {
??????????????? render(mv, processedRequest, response);
??????????? }
????????????? ........
??? }

这样具体的MVC模型的实现就由bean配置文件里定义好的view resolver,handler这些类来实现用户代码的功能。
总结上面的过程,我们看到在web容器中,ServletContext可以持有一系列的web上下文,而在整个web上下文中存在一个根上下文来作为其它 Servlet上下文的父上下文。这个根上下文是由ContextLoader载入并进行初始化的,对于我们的web应用, DispatcherSerlvet载入并初始化自己的上下文,这个上下文的父上下文是根上下文,并且我们也能从ServletContext中根据 Servlet的名字来检索到我们需要的对应于这个Servlet的上下文,但是根上下文的名字是由Spring唯一确定的。这个 DispactcherServlet建立的上下文就是我们开发Spring MVC应用的IOC容器。
具体的web请求处理在上下文体系建立完成以后由DispactcherServlet来完成,上面对MVC的运作做了一个大致的描述,下面我们会具体就SpringMVC的框架实现作一个详细的分析。

  相关解决方案