SpringBoot2.x(五)启动方式启动原理

发布时间:2026/7/28 14:59:14
SpringBoot2.x(五)启动方式启动原理 启动方式jar包启动需引入springboot应用maven构建插件主要用来指定应用启动类build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /buildjar包目录结构example.jar | -META-INF | -MANIFEST.MF -org | -springframework | -boot | -loader | -spring boot loader classes -BOOT-INF -classes | -mycompany | -project | -YourClasses.class -lib -dependency1.jar -dependency2.jarmvn spring-boot:run如果项目是maven目录结构可以进入项目根目录输入maven命令mvn 项目名:run来启动部署war包到tomcat9在pom.xml中设置打包方式为war在pom.xml的build节点下指定项目名如finalNamespringboot-demo/finalName更改启动类如下:public class Application extends SpringBootServletInitializer { Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(XdclassApplication.class); } public static void main(String[] args) throws Exception { SpringApplication.run(XdclassApplication.class, args); } }打包mvn install将target中的war包放入tomcat9并启动tomcat访问 http://localhost:8080/springboot-demo/testExstartup.bat闪退怎么办如果你的OS是windows也许你碰到过通过startup.bat启动tomcat命令行闪退的情况。那通常是一些配置异常导致的你可以在该文件的末尾加上一句pause;该命令行遇到异常时就会暂停而不会闪退至此你可以从中发现异常点。linux用户在tomcat/logs/catlina.out查看tomcat启动日志启动容器和第三方测试数据常见的javaweb的启动容器有tomcat、jetty、undertowJmterJmter是一个第三方测试容器性能的工具有兴趣的可以参见 https://examples.javacodegeeks.com/enterprise-java/spring/tomcat-vs-jetty-vs-undertow-comparison-of-spring-boot-embedded-servlet-containers/ 自学一下。启动原理概述springboot应用启动大致分两步从SpringApplication.run(Application.class, args);追溯到run(new Class?[] { primarySource }, args)再到new SpringApplication(primarySources).run(args)可发现分为以下两步1.SpringApplication(primarySources)此步主要为应用启动做准备如判断应用类型是否为web应用、初始化spring工厂实例、初始化监听器public SpringApplication(Class?... primarySources) { this(null, primarySources); }public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) { //null this.resourceLoader resourceLoader; //断言启动类不为空 Assert.notNull(primarySources, PrimarySources must not be null); this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass deduceMainApplicationClass(); }webApplicationTypeprivate WebApplicationType deduceWebApplicationType() { if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }这里会判断当前应用是否为web应用查看WebApplicationType可知有三种枚举类型分别是NONE不是web应用、SERVELT需要tomcat、jetty或undertow这样的servelt容器、REACTIVE这个跟之后涉及到的WebFlux函数式编程有关。setInitializers加载用来初始化spring容器的工厂实例。这些工厂类位于META-INF/spring.factories中你能在spring-boo.jar或spring-boot-devtool.jar中看到private T CollectionT getSpringFactoriesInstances(ClassT type,Class?[] parameterTypes, Object... args) { ClassLoader classLoader Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates SetString names new LinkedHashSet( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); ListT instances createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } private T ListT createSpringFactoriesInstances(ClassT type, Class?[] parameterTypes, ClassLoader classLoader, Object[] args, SetString names) { ListT instances new ArrayList(names.size()); for (String name : names) { try { Class? instanceClass ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor? constructor instanceClass.getDeclaredConstructor(parameterTypes); T instance (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( Cannot instantiate type : name, ex); } } return instances; }deduceMainApplicationClass()该方法遍历栈踪迹去找一个包含叫main字符串的栈元素来取得应用的启动类。private Class? deduceMainApplicationClass() { try { StackTraceElement[] stackTrace new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if (main.equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }2.run(String... args)public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context null; CollectionSpringBootExceptionReporter exceptionReporters new ArrayList(); configureHeadlessProperty(); //获取运行时监听并启动 SpringApplicationRunListeners listeners getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments new DefaultApplicationArguments(args); ConfigurableEnvironment environment prepareEnvironment(listeners,applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner printBanner(environment); context createApplicationContext(); exceptionReporters getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); ...stopWatchstopWatch主要用来计时可以提取反映容器性能指标printBanner准备要打印的bannercreateApplicationContext创建spring容器启动原理尚未明朗有待后续学习更多学习资料搜索