springmvc其实就是对servlet的封装
看源码需要搞清楚一下几个问题
- springmvc是如何和servlet整合
- springmvc是如何与ioc整合
一、springmvc是如何与servlet整合
servlet 3.0 规范提到
总结 : servlet容器在启动的时候回加载实现 ServletContainerInitializer 位置放到META-INF/services .他会回调里面的的方式,通过在类上面添加注解HandlesTypes(接口) 他可以是实现类,接口,抽象类。都会被加载。
The onStartup method of the ServletContainerInitializer will be invoked when the application is coming up before any of the servlet listener events are fired.
ServletContainerInitializer
这个意思: 实现类初始化
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
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)
ReflectionUtils.accessibleConstructor(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;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
// 在这里进行初始化处理
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
初始化上下文
org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 调用上下文加载器初始化类的onStartup方法
super.onStartup(servletContext);
// 注册DispatcherServlet
registerDispatcherServlet(servletContext);
}
org.springframework.web.context.AbstractContextLoaderInitializer#onStartup
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
org.springframework.web.context.AbstractContextLoaderInitializer#registerContextLoaderListener
protected void registerContextLoaderListener(ServletContext servletContext) {
// 创建root容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
// 把上下文加载监听器加载到servlet容器
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContext
protected WebApplicationContext createRootApplicationContext() {
// 定义根容器 @Service @Responsitory
Class<?>[] configClasses = getRootConfigClasses();
// 配置类是否为空
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
else {
return null;
}
}
AnnotationConfigWebApplicationContext 类导航
org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyAnnotationConfigDispatcherServletInitializer#getRootConfigClasses
protected Class<?>[] getRootConfigClasses() {
return null;
}
总结: 当servlet容器启动的是否首先会加载实现ServletContainerInitializer,然后通过注解 @HandlesTypes 解析出来改接口所有集成与实现类,抽象。然后调用 onStartup类。将注册接口相关的类通过参数的形式传递到该方法中,如果是实现类。就初始化,然后回调onStartup进行下一步操作。registerContextLoaderListener该方法主要做了创建根容器,并将根容器注册到ioc。 把上下文加载监听器加载到servlet容器(如果更容器存在,就把注册到servlet容器)
注册DispatchServlet )——(重点)
registerDispatcherServlet(servletContext);
protected WebApplicationContext createServletApplicationContext() {
// 创建基于注解的web应用上下文
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// 从子类实现中或者从@Configuration、@Component注解配置中获取配置类
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
// 注册@Configuration配置的配置加载类到AnnotationConfigWebApplicationContext
context.register(configClasses);
}
return context;
}
org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyAnnotationConfigDispatcherServletInitializer#getServletConfigClasses
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {MyConfiguration.class};
}
org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyConfiguration
@Configuration
public static class MyConfiguration {
@Bean
public MyBean bean() {
return new MyBean();
}
}
注册派生@Configuration、@Component
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
// 获取filteName
String filterName = Conventions.getVariableName(filter);
// 添加filter到servlet容器
Dynamic registration = servletContext.addFilter(filterName, filter);
// 如果filter注册失败
if (registration == null) {
int counter = 0;
while (registration == null) {
if (counter == 100) {
throw new IllegalStateException("Failed to register filter with name '" + filterName + "'. " +
"Check if there is another filter registered under the same name.");
}
//添加filter#0 到servlet容器
registration = servletContext.addFilter(filterName + "#" + counter, filter);
counter++;
}
}
registration.setAsyncSupported(isAsyncSupported());
registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName());
return registration;
}
总结:创建servlet上下文。注册dispatchServlet对象,同时注册过滤器。