javaee标准中,tomcat等web容器启动时走web.xml 先将各种contex-param 放到servletcontxt中变成parameter,然后开始启动容器,容器对外提供了listener可在容器onstartup时做一些操作。
log:
二月 25, 2017 2:56:16 下午 org.apache.catalina.core.ApplicationContext log
信息: No Spring WebApplicationInitializer types detected on classpath
解释:---没找到自定义的spring WebApplicationInitializer
这句日志来自于: org.springframework.web.SpringServletContainerInitializer 在spring-web-x.x.x.Release.jar 包中。
该类实现了servletContainerInitializer 接口的onStartup方法。此接口只有一个方法。这是spring3.1之后的新特性,无web.xml 而是基于代码注解的配置启动servlet。引入了servlet3.0.
* @param c the Set of application classes that extend, implement, or
* have been annotated with the class types specified by the
* {@link javax.servlet.annotation.HandlesTypes HandlesTypes} annotation,
* or <tt>null</tt> if there are no matches, or this
* <tt>ServletContainerInitializer</tt> has not been annotated with
* <tt>HandlesTypes</tt>
c这个param比较有意思,需要实现类增加@HandlesTypes(xx.class)注解。如spring的实现类声明了注解
@HandlesTypes(WebApplicationInitializer.class) 所以spring基于java代码的配置是需要实现WebApplicationInitializer接口的。
@since Servlet 3.0
public interface ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException;
}
查看此接口的注释
<p>Implementations of this interface must be declared by a JAR file
* resource located inside the <tt>META-INF/services</tt> directory and
* named for the fully qualified class name of this interface, and will be
* discovered using the runtime's service provider lookup mechanism
* or a container specific mechanism that is semantically equivalent to
* it.
大概意思是讲 必须在该接口所在项目的META-INF/services/文件夹下 生成一个文件名字为javax.serlvet.ServletContainerInitializer的文件,内容要与ServletContainerInitializer接口的实现类的全路径一样才能被发现。
仔细看spring-web包下 有类似的结构。声明为了javax.servlet.ServletContainerInitializer的文件,内容为 org.springframework.web.SpringServletContainerInitializer
日志来自于实现类:SpringServletContainerInitializer上一段源码:
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) waiClass.newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
AnnotationAwareOrderComparator.sort(initializers);
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
因为没有使用基于servlet3.0规范的类,所以有这一条日志。
log:
Initializing Spring root WebApplicationContext
解释:日志是由类
WebApplicationContextorg.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext servletContext)打印的,contextLoader作为ContextLoaderListener的private 变量。标识着启动wac。核心代码在wac.refresh()中。
值得注意的是注册核心类之前,会先处理beanFactory的PostProcesors类。
这些类一般都实现了
BeanFactoryPostProcessor 这个接口。通常讲抽象类PropertyResourceConfigurer比较重要。
org.springframework.beans.factory.config.PropertyResourceConfigurer
源码注释:
/* Allows for custom modification of an application context's bean definitions, * adapting the bean property values of the context's underlying bean factory. * * <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in * their bean definitions and apply them before any other beans get created. * * <p>Useful for custom config files targeted at system administrators that * override bean properties configured in the application context.
*/
LOG:
2017-02-25 19:29:08:719 INFO [mvc.annotation.DefaultAnnotationHandlerMapping] Mapped URL path
解释:
启动wac时,会由读取@RequestMapping 注解拼接url ,并缓存 {url,method}的映射关系。
LOG:
二月 25, 2017 7:40:29 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring FrameworkServlet 'led'
2017-02-25 19:40:29:584 INFO [web.servlet.DispatcherServlet] FrameworkServlet 'led': initialization started
2017-02-25 19:40:29:603 INFO [context.support.XmlWebApplicationContext] Refreshing WebApplicationContext for namespace 'led-servlet': startup date [Sat Feb 25 19:40:29 CST 2017]; parent: Root WebApplicationContext
2017-02-25 19:40:29:605 INFO [factory.xml.XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/led-servlet.xml]
解释:开始启动servlet,配置为DispatcherServlet 并执行父类 FrameworkServlet 的父类 HttpServletBean的init方法,并钩子调用FrameworkServlet的initServletBean()创建servlet容器 放到servletContext
setAttribute(Framework.class.getName()+".CONTEXT"+ServletName,WAC);并且将WAC的parent设置为ContextLoaderListener创建的WAC。
至此SpringMVC启动完毕。
更加详细的内容下一篇随笔。