1 在老版的springmvc中 是需要在xml中指定一个监听器
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
ContextLoaderListener这个监听器实现了servlet规范中的一个接口 ServletContextListener,
在tomcat启动的某个节点会来调用到这里 从而完成spring容器的初始化
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
xml中还会初始化一个dispatchServlet 这个大家都很熟悉 请求从tomct调用到这个sevlet做一系列处理
2 在基于代码配置中
基于spring官网的介绍Web on Servlet Stack
import org.springframework.web.WebApplicationInitializer;
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
这里就是初始化了容器和创建了dispatchSerlet到tomcat中 但为啥这样就可以了 原理是servlet3.0规范
1 实现了这个接口的类要加在META-INF/services/javax.servlet.ServletContainerInitializer文件中才会生效
2 实现了这个接口的类,这个类上被加了@HandlesTypes注解的类会被注入到这个类的onStartup方法的第一个参数中,也就是Set集合
3 servlet容器在启动的时候要调用这个类的onStartup方法
package javax.servlet;
import java.util.Set;
/**
* 定义在META-INF/services/javax.servlet.ServletContainerInitializer文件中
*
* @since Servlet 3.0
*/
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}
}
}
}
这里WebApplicationInitializer就是上面图中的父接口 这样就实现了0配置
这里重点提一句 springboot是内置的tomct 初始化容器在run方法里 不要被SpringBootServletInitializer误导了,dispatchSetvlet是在WebMvcAutoConfiguration里的DispatcherServletAutoConfiguration初始化的
多提下springmvc组件注册过程
1 老版的springmvc是在DispatcherServlet的initStrategies中注册的
2 springboot中是基于自动装配
总结:
springmvc这些bean的注入 因为老版一般是打成war包 放到tomcat容器中,新版的内置的tomcat,所以玩法都不同 了 但肯定是有一个地方去做这些事,包括组件的注册过程,都会伴随着框架的特性去做调整 这里就展示了springboot 约定大于配置 ,不需要你配置dispatchServlet 而是自动帮你注入一个
1 需要初始化spring容器,老版是tomcat实现sevlet规范基于spi去加载,springboot直接run里初始化
2 需要注入dispatchSevlet,老版是配置xml中,springboot自动装配
3 需要注入mvc的组件,老版是dispachservelet的的父类serlet的init方法,springboot自动装配