spring boot war包启动原理


spring boot用了小两年,war包发布也用过多次了。今天纠结了下它的启动原理,网上查了下资料,感觉不够精简,于是自己总结了一下。
 
实现
spring boot项目打war包很简单,项目main application class继承 SpringBootServletInitializer,pom文件中packaging配置为war即可。

spring boot main application class

@SpringBootApplication
public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

 

原理
简而言之,spring boot war启动是利用Servlet 3.0新增的ServletContainerInitializer接口结合SPI(Service Provider Interface)机制实现的。
 主要逻辑
  1. Spring在spring-web-version.jar/META-INF/services/javax.servlet.ServletContainerInitializer文件中,配置了spring对ServletContainerInitializer接口的实现类org.springframework.web.SpringServletContainerInitializer。
  2. Servlet Container启动阶段扫描jar包中META-INF/services/javax.servlet.ServletContainerInitializer文件, 获取ServletContainerInitializer实现类并实例化,解析ServletContainerInitializer上@HandlesTypes注解,查找出@HandlesTypes限定的类型集合,作为ServletContainerInitializer.onStartup 方法处理的第一个参数c。
  3. Servlet Container依次调用每个ServletContainerInitializer实例的onStartup。war包启动的场景中会调用SpringServletContainerInitializer.onStartup方法,该方法循环调用c集合中每个 WebApplicationInitializer子类(即SpringBootServletInitializer)的onStartup方法。
  4. SpringBootServletInitializer.onStartup方法调用SpringBootServletInitializer.createRootApplicationContext方法,createRootApplicationContext方法中构建SpringApplication并执行SpringApplication.run方法以启动整个spring项目。

关键源码

Spring的ServletContainerInitializer实现类

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
......
     @Override
     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);
          }
     }
}

 

WebApplicationInitializer.class接口的实现类

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
......
     @Override
     public void onStartup(ServletContext servletContext) throws ServletException {
          // Logger initialization is deferred in case an ordered
          // LogServletContextInitializer is being used
          this.logger = LogFactory.getLog(getClass());
          WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
          ......//略去部分代码
     }

     protected WebApplicationContext createRootApplicationContext(
              ServletContext servletContext) {
          SpringApplicationBuilder builder = createSpringApplicationBuilder();
          builder.main(getClass());
          ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
          ......//略去部分代码
          return run(application);
     }

    protected WebApplicationContext run(SpringApplication application) {
          return (WebApplicationContext) application.run();
     }

}

 

转载请注明出处,尊重彼此的劳动成果。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM