Spring Boot启动过程源码分析

本文详细解析了SpringBoot启动过程中的关键步骤,包括初始化器、监听器及Runners的使用方法,并介绍了如何自定义这些组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自:http://blog.youkuaiyun.com/dm_vincent/article/details/76735888
              http://blog.youkuaiyun.com/dm_vincent/article/details/77151122

Spring Boot的启动始于:
SpringApplication.run(DemoApplication.class, args);
相应实现:
	public static ConfigurableApplicationContext run(Object source, String... args) {
		return run(new Object[] { source }, args);
	}
	public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
		return new SpringApplication(sources).run(args);
	}
它实际上会构造一个SpringApplication的实例,然后运行它的run方法:
	public SpringApplication(Object... sources) {
		initialize(sources);
	}
	private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		this.webEnvironment = deduceWebEnvironment();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
deduceWebEnvironment()是推断应用类型是Standard还是Web,方法是在当类路径中找是否存在"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"的类来判断的。

然后设置初始化器,会从类路径的META-INF/spring.factories处读取相应配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot这个包为例,它的META-INF/spring.factories部分定义如下所示:
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
因此这几个类名会实例化出来放在SpringApplication 的initializers中。

之后设置监听器,同上读取配置文件中Key为:org.springframework.context. ApplicationListener的value,然后加载实例化后,设置在listeners中。
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

然后设置mainApplicationClass:
	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;
	}
它通过构造一个运行时异常,通过异常栈中方法名为main的栈帧来得到入口类的名字。至此,对于SpringApplication实例的初始化过程就结束了。

完成了实例化,下面开始调用run方法:
	public ConfigurableApplicationContext run(String... args) {
                // 计时工具
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
                // 设置java.awt.headless系统属性为true - 没有图形化界面
		configureHeadlessProperty();

		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
		    ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
		    ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
           
                    // Banner打印器,就是启动Spring Boot的时候打印在console上的	
		    Banner printedBanner = printBanner(environment);

                    // 创建Spring上下文
		    context = createApplicationContext();
		    analyzers = new FailureAnalyzers(context);

                    // Spring上下文前置处理
		    prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);

		    refreshContext(context);

                    // Spring上下文后置处理
	 	    afterRefresh(context, applicationArguments);
		    listeners.finished(context, null);
		    stopWatch.stop();
		    if (this.logStartupInfo) {
			    new StartupInfoLogger(this.mainApplicationClass)
				    .logStarted(getApplicationLog(), stopWatch);
		    }
		    return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
createApplicationContext()即创建Spring的主要组件ApplicationContext,对于Web应用,上ApplicationContext就是AnnotationConfigEmbeddedWebApplicationContext。refreshContext(context)即刷新ApplicationContext:
	private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
最终会调用到我们熟知的AbstractApplicationContext的refresh()方法。

上下文后置处理afterRefresh()方法:
	protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
		callRunners(context, args);
	}

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
所谓的后置操作,就是在容器完成刷新后,依次调用注册的Runners。Runners可以是两个接口的实现类:org.springframework.boot.ApplicationRunner与org.springframework.boot.CommandLineRunner。


基于上面的了解,我们就可以在Spring Boot启动添加自定义的初始化器、监听器等。
添加定制化的初始化器:
public static void main(String[] args) {

    // 创建SpringApplication的实例
    SpringApplication app = new SpringApplication(Application.class);

    // 添加定制的初始化器
    app.addInitializers(new CustomApplicationContextInitializer());

    // 执行SpringApplication实例的run方法
    app.run(args);
}
public class CustomApplicationContextInitializer implements ApplicationContextInitializer {
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationContextInitializer.class);

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        LOGGER.info("自定义的初始化器的initialize方法被执行了");
    }
}

添加定制化的监听器:
app. addListeners(new CustomApplicationListener());
public class CustomApplicationListener implements ApplicationListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationListener.class);

    public void onApplicationEvent(ApplicationEvent event) {
        // 监听ApplicationStartingEvent
        if (event instanceof ApplicationStartedEvent) {
            logInfo("ApplicationStartedEvent listened");
        }

        // 监听ApplicationEnvironmentPreparedEvent
        else if (event instanceof ApplicationEnvironmentPreparedEvent) {
            logInfo("ApplicationEnvironmentPreparedEvent listened");
        }

        // 监听ApplicationPreparedEvent
        else if (event instanceof ApplicationPreparedEvent) {
            logInfo("ApplicationPreparedEvent listened");
        }


        // 监听ApplicationReadyEvent
        else if (event instanceof ApplicationReadyEvent) {
            logInfo("ApplicationReadyEvent listened");
        }

        // 监听ApplicationFailedEvent
        else if (event instanceof ApplicationFailedEvent) {
            logInfo("ApplicationFailedEvent listened");
        }
    }

    private void logInfo(String log) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info(log);
        }
    }
}

添加定制化的后置Runners:
@Component
@Order(2)
public class CustomApplicationRunner implements ApplicationRunner {
  private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationRunner.class);

  @Override
  public void run(ApplicationArguments arg) {
      if (LOGGER.isInfoEnabled()) {
          LOGGER.info("自定义ApplicationRunner运行了");
      }
  }
}
@Component
@Order(1)
public class CustomCommandLineRunner implements CommandLineRunner {
  private static final Logger LOGGER = LoggerFactory.getLogger(CustomCommandLineRunner.class);

  @Override
  public void run(String... strings) throws Exception {
      if (LOGGER.isInfoEnabled()) {
          LOGGER.info("自定义CommandLineRunner运行了");
      }
  }
}
       自定义Runner的添加方式和上述的初始化器以及监听器有点不同,就是Runners直接通过@Component注解添加即可,借助于包扫描机制,它们会被注册到容器中。至于它们运行的顺序,则可以通过上述的@Order注解来完成标注,数值越小的Runner优先级越高,因为源码中有AnnotationAwareOrderComparator.sort(runners),因此上面代码中,CustomCommandLineRunner将先于CustomApplicationRunner被执行。

启动打印Banner:
扩展的方式也很简单,看源代码就清楚该怎么扩展了:
	private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值