spring web服务在tomcat容器中启动的流程
在介绍spring启动流程之前,先介绍2个概念 servlet ,ServletContext。
servlet 是java web服务的核心组件,可以简单理解为servlet是能接收并处理web请求的服务(典型的就是http请求)
ServletContext 是生成并维护servlet的上下文,存在于特定容器之中,如tomcat,jetty,resin等等
容器启动过程中解析web.xml 文件,它描述了一个web服务的关键信息,一般情况下包括servlet 、filter、listener 。
容器启动时将通知相关的listener,一般情况下spring环境就是这个时候引入的。
执行相关Servlet(如果设置为容器启动时执行)
filter初始化并执行init方法
filter在servlet接收请求过程中之前都会执行
下面介绍spring 是如何在web环境中被初始化的
StandardContext.listenerStart() 启动web.xml 中配置的监听器(这个监听器在容器初始化时执行)
这里的StandardContext就是tomcat容器中的servlet环境
从上面可以看出,启动过程为,tomcat容器读取web.xml 初始化servlet容器StandardContext,配置listener,filter,servlet,初始化成功后触发相应的监听器,servlet(如果设置为load-on-startup)
现在看集成spring的web项目一般的web.xml示例:
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>zhixiao.root</param-value>
</context-param>
<!-- session timeout, minutes unit -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<!-- default home page -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<display-name>parking Created Web Application</display-name>
<!-- sprint/* -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener> <!-- 可以去掉,因为spring mvc 的DispatchServlet 支持request session 作用范围的bean -->
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- Spring 刷新Introspector防止内存泄露 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- encoding -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- redis session接管 -->
<filter>
<display-name>RedisSessionFilter</display-name>
<filter-name>RedisSessionFilter</filter-name>
<filter-class>com.qhyu.zhixiao.session.RedisSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RedisSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<!-- ip checking -->
<filter>
<filter-name>ipFilter</filter-name>
<filter-class>com.qhyu.zhixiao.filter.IpFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ipFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<!-- springmvc -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
</web-app>
下面重点看 ContextLoaderListener
这个listener在tomcat容器启动时执行
publicclass ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* Initialize the root web application context.
*/
@Override
publicvoid contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
@Override
publicvoid contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
initWebApplicationContext 方法就是初始化spring的入口,参数就是tomcat容器初始化的servlet
进入
initWebApplicationContext方法主要干了两件事
1.初始化WebApplicationContext
WebApplicationContext context = null;
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
通过java反射机制生成ConfigurableWebApplicationContext类对象,它就是spring的bean生成运行环境(BeanFactory容器)
2. 刷新初始化webApplication
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
configureAndRefreshWebApplicationContext(cwac,servletContext);
生成好spring上下文对象后,进入configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)方法,主要执行代码如下:
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);//为spring 上下文设置spring bean配置文件路径
}
ConfigurableEnvironment env = wac.getEnvironment();
if (envinstanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
这里有一个注意的地方,ConfigurableEnvironment生成的地方,
wac.setConfigLocation(configLocationParam); 时根据 configLocationParam设置配置参数路径时就会初始化StandardServletEnvironment(ConfigurableEnvironment的子类)
进入AbstractApplicationContext.refresh()方法
publicvoid refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throwex;
}finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
(1)prepareRefresh()
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
(2) obtainFreshBeanFactory();此方法负责创建beanFactory并根据spring xml配置文件初始化得到BeanDefintions
这里主要看XmlWebApplicationContext类的loadBeanDefinitions方法
从上图看一看出,是如何一步一步的解析xml文件的
主要代码在NamespaceHandler中,根据命名空间得到相应的处理器来解析相关配置文件中的标签tag
得到的handler为:org.springframework.context.config.ContextNamespaceHandler
其实就是从spring的jar包配置文件中获取的
publicclass ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
publicvoid init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
应该可以明显看出,xml中的标签就是通过这些handler来处理的
通过handler中注册的parser来解析tag
下面再来看下是如何解析的
通过tag名称,得到相应的解析器并做相应的处理
上面实例就是解析property-placeholder标签的parser
回到refresh()方法,可以看到obtainFreshBeanFactory();其实已经干了大部分工作了,创建spring bean上下文beanFactory 并解析xml得到beanDefintion初始化上下文。
下一步执行prepareBeanFactory(beanFactory);方法
这个方法主要是对beanFactory做一些初始化工作
1)设置classLoader
2)设置SpEL表达式解析
3)设置ResourceEditorRegistrar(在获取bean中设置value)
4)设置前置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
5)设置一些不需要autowired的bean
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
ApplicationContextAware子类不通过autowired方式注入
6)设置和环境相关的beans
prepareBeanFactory之后执行postProcessBeanFactory
主要设置了一些前置处理器。
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
后续就是注册资源文件,监听器,实例化一些非延迟加载的bean,最后广播相关事件 over
总结:
spring家族中所有的部件都是基于spring bean容器的,了解beanFactory上下文的结构和原理对理解spring十分重要,本文主要从整体上描述了spring 如何在web环境中初始化启动,从源码上给出了一个简要的流程描述,希望读者仔细阅读后能对spring 的bean容器有一个系统的了解。
参考:
2.http://www.cnblogs.com/RunForLove/p/5688731.html
相关推荐
在Spring框架中,Bean的创建和初始化是IoC(Inversion of Control)容器的核心功能,这一过程涉及到多个步骤。以下是对Spring Bean创建初始化流程的详细解释: 1. **初始化ApplicationContext**: 开始时,通过`...
ApplicationContextInitializer 是 Spring 上下文初始化类,负责加载配置文件和注册 Bean。通过查看源码,我们可以发现 Spring 自动加载配置文件的代码。 SpringApplication 运行 SpringApplication 的 run 方法是...
在Spring应用中,Context通常通过`ApplicationContext`接口来实例化,如`ClassPathXmlApplicationContext`或`FileSystemXmlApplicationContext`,这些类用于加载XML配置文件并初始化bean。 创建自定义对象的基本...
6. **Bean的作用域**:默认情况下,Spring Bean的作用域是Singleton,意味着在整个应用上下文中只有一个实例。如果将Bean设置为Prototype,那么每次请求都会创建一个新的实例,可能导致重复执行。 7. **XML配置中的...
在此阶段,ApplicationContext会初始化如MessageSource这样的内建Bean,提供消息国际化服务,以及初始化Spring事件广播器,使得事件驱动的通信成为可能。 7. **Spring 应用上下文刷新阶段** 刷新过程涉及Bean的...
如果某个Bean需要访问到Spring的全局ApplicationContext,它可以实现这个接口,Spring会在初始化时自动注入ApplicationContext实例。这样,WebApplicationContext就可以访问到由全局ApplicationContext管理的Bean,...
2. `AsyncProxyBeanPostProcessor`:此处理器可能用于创建代理对象,确保异步初始化方法在正确的上下文中执行。代理对象能够拦截调用并将其转换为异步操作。 3. `BeanDefinitionUtil`:这个工具类可能包含了对bean...
定制上下文可以通过提供上下文初始化器类来实现,这些类通过`contextInitializerClasses`属性定义。这些初始化器可以在ApplicationContext启动前对其进行自定义配置,增强了Spring的灵活性。 在启动上下文阶段,...
在Web应用中,Spring通常会创建一个WebApplicationContext,它与Servlet上下文(ServletContext)关联。 **方法一:使用WebApplicationContextUtils** 在Servlet中,我们可以利用`WebApplicationContextUtils`工具...
在Spring框架中,Bean的管理是其核心特性之一,它涉及到Bean的创建、初始化、装配以及销毁等整个生命周期过程。本课件主要涵盖了以下几个关键知识点: 1. **控制反转(IoC)和依赖注入(DI)**:Spring的核心设计...
1. **ApplicationContext**:这是Spring提供的一个接口,代表了Spring的上下文,包含了bean的定义和bean的实例。我们可以使用`ApplicationContext`来获取bean。例如: ```java ApplicationContext context = new ...
当Web容器启动时,Spring的初始化过程会创建`XmlWebApplicationContext`实例,并调用`refresh()`方法来加载bean定义。这个过程主要由`loadBeanDefinitions()`方法完成,它使用`XmlBeanDefinitionReader`来解析XML...
2. **RequestContextListener**:这个监听器帮助初始化和清理Web上下文,确保每个请求都有一个独立的上下文环境。 四、Spring Web服务 除了MVC,Spring Web还支持Web服务的创建和消费。在3.0.0.RC3版本中,Spring...
为了读取YAML配置,你需要在Spring Boot应用的启动类或者其他适当的初始化点,注册`@EnableConfigurationProperties`注解,指定配置属性类。例如,如果你有一个名为`ConfigProps`的类,其中包含了YAML文件中的属性:...
`ContextLoaderListener`的`contextInitialized`方法主要负责调用`initWebApplicationContext`方法,该方法在`ContextLoader`类中实现,其作用是初始化Web环境下的Spring应用上下文(ApplicationContext)。...
Spring2.0 以后,增加了 session、request、global session 三种专用于 Web 应用程序上下文的 Bean。因此,默认情况下 Spring2.0 现在有五种类型的 Bean。当然,Spring2.0对 Bean 的类型的设计进行了重构,并设计出...
这种配置方式下,Spring的初始化和Bean管理是在Struts的Action上下文中完成的,而不是直接在`web.xml`中配置。 Struts2的Spring插件会在Struts配置文件(如struts.xml)中定义一个`<package>`,包含`<interceptors>...
在`web.xml`中配置Listener时,其加载顺序通常发生在所有其他组件之前,因为它们经常用于初始化应用程序环境或配置Spring容器。 **示例代码:** ```xml org.springframework.web.context....
Spring Context作为一个全局的应用上下文,提供了加载配置、管理Bean、事件传播等功能。开发者可以通过ApplicationContext接口访问和操作Bean,同时也可以利用@PostConstruct和@PreDestroy注解来控制Bean的初始化和...
- `<listener>`:定义了一个`ContextLoaderListener`监听器,当Web应用启动时,它会读取`context-param`中指定的配置文件,初始化Spring应用上下文。 4. **创建`applicationContext.xml`**: 这是Spring的配置...