疑问:传统servlet项目是如何集成到springboot项目中的?为何无需再配置web.xml
原理:servlet3.0配置api+spring抽象实现AbstractAnnotationConfigDispatcherServletInitializer
servlet3.0配置api: 基于ServletContainerInitializer接口实现与@HandlesTypes过滤出
WebApplicationInitializer具体实现类集合,而AbstractAnnotationConfigDispatcherServletInitializer的默认实现,就配置了DisPachservlet(AbstractAnnotationConfigDispatcherServletInitializer父类中实现了),从而可以自动装备
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
-
- package org.springframework.web;
-
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Set;
- import javax.servlet.ServletContainerInitializer;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.HandlesTypes;
- import org.springframework.core.annotation.AnnotationAwareOrderComparator;
- import org.springframework.lang.Nullable;
- import org.springframework.util.ReflectionUtils;
-
- @HandlesTypes({WebApplicationInitializer.class})
- public class SpringServletContainerInitializer implements ServletContainerInitializer {
- public SpringServletContainerInitializer() {
- }
-
- public void onStartup(@Nullable Set
> webAppInitializerClasses, ServletContext servletContext) throws ServletException { - List
initializers = Collections.emptyList(); - Iterator var4;
- if (webAppInitializerClasses != null) {
- initializers = new ArrayList(webAppInitializerClasses.size());
- var4 = webAppInitializerClasses.iterator();
-
- while(var4.hasNext()) {
- Class> waiClass = (Class)var4.next();
- if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
- try {
- ((List)initializers).add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
- } catch (Throwable var7) {
- throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
- }
- }
- }
- }
-
- if (((List)initializers).isEmpty()) {
- servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
- } else {
- servletContext.log(((List)initializers).size() + " Spring WebApplicationInitializers detected on classpath");
- AnnotationAwareOrderComparator.sort((List)initializers);
- var4 = ((List)initializers).iterator();
-
- while(var4.hasNext()) {
- WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
- initializer.onStartup(servletContext);
- }
-
- }
- }
- }
spring抽象实现AbstractAnnotationConfigDispatcherServletInitializer:WebApplicationInitializer具体抽象,可装备dispachServlet
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
-
- package org.springframework.web.servlet.support;
-
- import org.springframework.lang.Nullable;
- import org.springframework.util.ObjectUtils;
- import org.springframework.web.context.WebApplicationContext;
- import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
-
- public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
- public AbstractAnnotationConfigDispatcherServletInitializer() {
- }
-
- @Nullable
- protected WebApplicationContext createRootApplicationContext() {
- Class>[] configClasses = this.getRootConfigClasses();
- if (!ObjectUtils.isEmpty(configClasses)) {
- AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
- context.register(configClasses);
- return context;
- } else {
- return null;
- }
- }
-
- protected WebApplicationContext createServletApplicationContext() {
- AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
- Class>[] configClasses = this.getServletConfigClasses();
- if (!ObjectUtils.isEmpty(configClasses)) {
- context.register(configClasses);
- }
-
- return context;
- }
-
- @Nullable
- protected abstract Class>[] getRootConfigClasses();
-
- @Nullable
- protected abstract Class>[] getServletConfigClasses();
- }
springboot如何推断是web应用:
SpringApplication 在run方法之前推断,只能检查当前classLoader存在class存在,来判断是否为web应用。
判断标准:是否有Servlet和ConfigurableWebApplicationContext,有则为web servlet项目即传统springmvc
javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
-
- package org.springframework.boot;
-
- import org.springframework.util.ClassUtils;
-
- public enum WebApplicationType {
- NONE,
- SERVLET,
- REACTIVE;
-
- private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
- private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
- private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
- private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
-
- private WebApplicationType() {
- }
-
- static WebApplicationType deduceFromClasspath() {
- if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
- return REACTIVE;
- } else {
- String[] var0 = SERVLET_INDICATOR_CLASSES;
- int var1 = var0.length;
-
- for(int var2 = 0; var2 < var1; ++var2) {
- String className = var0[var2];
- if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
- return NONE;
- }
- }
-
- return SERVLET;
- }
- }
- }
遗留问题:
AnnotationConfigWebApplicationContext即可扫描springmvc相关的注解,从而达到自动装备
文章:摘录部分《小马哥 springBoot编程思想》