在上一章中,我们介绍了springboot是如何启动一个内置tomcat的,看完之后你可能还有疑问,那么我的springmvc是什么时候配置的呢?为什么我在项目理解价格@requestMapping就能接收对应的请求呢?
我们知道,springmvc中最主要的就是Dispatcherservlet,也就是说,如果我们能动态往web容器中添加这么一个servlet,那么就能实现自动装配springmvc了,那么springboot又是什么时候把这个dispatcherServlet装载进容器的呢?
不知道在前面一章的讲解在tomcat启动过程中你有没有注意到有这样一段代码
getSelfInitializer().onStartup(servletContext);
这段代码其实就是去加载springmvc,那么他是如何做到的呢?getSelfInitializer()最终会去调用到ServletWebServerApplicationContext的selfInitialize方法,该方法代码如下
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
我们通过调试,知道getServletContextInitializerBeans()返回的是一个ServletContextInitializer集合,集合中有以下几个对象
然后依次去调用对象的onStartup方法,那么对于上图标红的对象来说,就是会调用到DispatcherServletRegistrationBean的onStartup方法,这个类并没有这个方法,所以最终会调用到父类RegistrationBean的onStartup方法,该方法代码如下
public final void onStartup(ServletContext servletContext) throws ServletException {
//获取当前环境到底是一个filter 还是一个servlet 还是一个listener
String description = getDescription();
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
register(description, servletContext);
}
这边register(description, servletContext);
会调用到DynamicRegistrationBean的register方法,代码如下
protected final void register(String description, ServletContext servletContext) {
D registration = addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
return;
}
configure(registration);
}
addRegistration(description, servletContext)
又会调用到ServletRegistrationBean中的addRegistration方法,代码如下
protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
String name = getServletName();
return servletContext.addServlet(name, this.servlet);
}
我们通过调试,即可知到this.servlet就是dispatcherServlet
看到这里明白了吧?
springboot自动装配springmvc其实就是往servletContext中加入了一个dispatcherservlet。
什么?Servlet还可以这样注入的吗?是的,Serclet3.0规范中有这个说明,除了可以动态加Servlet,还可以动态加Listener,Filter
到此为止,还有一个问题,那便是springboot是如何加装其他应用的呢?我们知道,比如我们要在项目里面使用Feign,我们只需要使用这样一个注解@EnableFeignClients
.那么这是如何做到的呢?
其实这涉及到如何在springboot中自定义starter,我有一篇文章,里面有写
SpringBoot自定义starter