The principle of spring and springMVC parent-child container

To understand the relationship between these three contexts, you need to be familiar with how spring is started in the web container. The startup process of spring is actually the startup process of its IoC container. For web programs, the startup process of the IoC container is the process of establishing the context.

The startup process of spring:

  1. First of all, for a web application, it is deployed in the web container, and the web container provides a global context, which is the ServletContext, which provides the host environment for the subsequent spring IoC container;

  2. Secondly, contextLoaderListener will be provided in web.xml. When the web container starts, the container initialization event will be triggered. At this time, the contextLoaderListener will listen to this event, and its contextInitialized method will be called. In this method, spring will initialize a startup context, which is called the root context, namely WebApplicationContext , which is an interface class, to be precise, its actual implementation class is XmlWebApplicationContext. This is spring's IoC container, and the configuration of its corresponding bean definition is specified by the context-param tag in web.xml. After the IoC container is initialized, spring uses WebApplicationContext.ROOT WEB APPLICATION CONTEXT ATTRIBUTE as the attribute Key and stores it in the ServletContext for easy access;

  3. Once again, after the contextLoaderListener listener is initialized, it starts to initialize the Servlet configured in web.xml. This servlet can be configured with multiple ones. Take the most common DispatcherServlet as an example, this servlet is actually a standard front-end controller for forwarding, Match and process each servlet request. The DispatcherServlet context will establish its own IoC context during initialization to hold spring mvc-related beans. When establishing DispatcherServlet's own IoC context, it will use WebApplicationContext.ROOT WEB APPLICATION CONTEXT ATTRIBUTE to obtain the previous root context (ie WebApplicationContext) from ServletContext as the parent context of its own context. After you have this parent context, initialize the context you hold. The work of this DispatcherServlet to initialize its own context can be seen in its initStrategies method. The general work is to initialize processor mapping, view resolution, and so on. The default implementation class of the context held by this servlet is also mlWebApplicationContext. After initialization, spring uses the attribute related to the name of the servlet (here, it is not simply named as the servlet key, but through some conversion, you can view the source code by yourself) as the attribute key, and also save it in the ServletContext, so that subsequent use. In this way, each servlet holds its own context, that is, has its own independent bean space, and each servlet shares the same beans, that is, those beans defined by the root context (the context initialized in step 2).

After talking about the initialization process of the spring context, the relationship between these three contexts should be understood. If it's still not clear, I can't help but look at the code by myself.

===============================================================================================================

最近在做项目时牵扯到有关父子上下文的概念。

何为父子上下文呢?

父上下文:

使用listener监听器来加载配置文件,如下:

?
1
2
3
< listener >   
   < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class >   
</ listener >

Spring 会创建一个WebApplicationContext上下文,称为父上下文(父容器),保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

可以使用Spring提供的工具类取出上下文对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

子上下文:

使用Spring MVC 来处理拦截相关的请求时,会配置DispatchServlet:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
< servlet >
     < servlet-name >dispatcherServlet</ servlet-name >
     < servlet-class >org.springframework.web.servlet.DispatcherServlet
     </ servlet-class >
     < init-param >
         < param-name >contextConfigLocation</ param-name >
         < param-value >/WEB-INF/applicationContext-mvc.xml</ param-value >
     </ init-param >
     < load-on-startup >1</ load-on-startup >
</ servlet >
 
< servlet-mapping >
     < servlet-name >dispatcherServlet</ servlet-name >
     < url-pattern >/</ url-pattern >
</ servlet-mapping >

每个DispatchServlet会有一个自己的上下文,称为子上下文,它也保存在 ServletContext中,key 是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一 个Request对象产生时,会把这个子上下文对象(WebApplicationContext)保存在Request对象中,key是 DispatcherServlet.class.getName() + ".CONTEXT"。

可以使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);


父上下文(父容器)和子上下文(子容器)的访问权限:

子上下文可以访问父上下文中的bean,但是父上下文不可以访问子上下文中的bean。


父上下文使用与否

方案一,传统型:

父上下文容器中保存数据源、服务层、DAO层、事务的Bean。

子上下文容器中保存Mvc相关的Action的Bean.

事务控制在服务层。

由于父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)。

当然,做为“传统型”方案,也没有必要这要做。

 

方案二,激进型:

Java世界的“面向接口编程”的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面。写一个小功能 7、8个类就写出来了。 开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能做好,小项目能做快。所以“激进型”方案就出现了-----没有接口、没有Service层、还可以没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。

本文不想说这是不是正确的思想,我想说的是Spring不会限制你这样做。

由于有了父子上下文,你将无法实现这一目标。解决方案是只使用子上下文容器,不要父上下文容器 。所以数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子上下文容器中。就可以实现了,事务(注解事务)就正常工作了。这样才够激进。

总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子上下文,只使用一个DispatcherServlet,事情就简单了,什么麻烦事儿也没有了。

 

 

 

Java--大项目能做好--按传统方式做,规规矩矩的做,好扩展,好维护。

Java--小项目能做快--按激进方式做,一周时间就可以出一个版本,先上线接受市场(用户)的反馈,再改进,再反馈,时间就是生命(成本)。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324462979&siteId=291194637