转载

SpringBoot源码 - 启动

常用的 SpringApplication.run(Class, Args) 启动Spring应用, 创建或者更新 ApplicationContext

静态方法run

使用source类实例化一个 SpringApplication 实例, 并调用实例方法 run .

public static ConfigurableApplicationContext run(Object[] sources, String[] args){
  return new SpringApplication(sources).run(args);
}

初始化initialize

  1. 实例化的时候首先通过尝试加载 javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext 推断当前是否是 web 环境.

  2. 然后从 spring.factories 获取 ApplicationContextInitializer 的实现类.

  3. spring.factories 获取 ApplicationListener 的实现类
  4. 推断出应用的启动类(包含main方法的类): 检查线程栈中元素的方法名是否是 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;
}

到此实例化就完成了.

实例方法run

public ConfigurableApplicationContext run(String... args){
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  //默认设置java.awt.headless为true
  configureHeadlessProperty(); 
  //从spring.factories中获取org.springframework.boot.SpringApplicationRunListener的实现类
  SpringApplicationRunListeners listeners = getRunListeners(args);
  //通过EventPublishingRunListener发布started事件
  listeners.started();
  try {
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(
        args);
    //重点: 创建更新上下文对象
    context = createAndRefreshContext(listeners, applicationArguments);
    //上下文对象更新完调用
    afterRefresh(context, applicationArguments);
    //通过EventPublishingRunListener发布finished事件
    listeners.finished(context, null);
    stopWatch.stop();
    if (this.logStartupInfo) {
      new StartupInfoLogger(this.mainApplicationClass)
          .logStarted(getApplicationLog(), stopWatch);
    }
    return context;
  }
  catch (Throwable ex) {
    handleRunFailure(context, listeners, ex);
    throw new IllegalStateException(ex);
  }
}

SpringApplicationRunListener

监听 SpringApplicationrun 方法. 通过 SpringFactoriesLoader 加载, 实现时需要提供public的构造方法接受 SpringApplicationString[] 为参数.

事件的发生顺序为 started -> environmentPrepared -> contextPrepared -> contextLoaded -> finished .

SpringBoot默认使用 EventPublishingRunListener 这个实现类, 将各个事件封装并发布出去, 最终被 ApplicationListener 捕获.

public interface SpringApplicationRunListener{
void started();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void finished(ConfigurableApplicationContext context, Throwable exception);
}

创建并更新上下文对象createAndRefreshContext

private ConfigurableApplicationContext createAndRefreshContext(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments){
  ConfigurableApplicationContext context;
  // Create and configure the environment
  //获取或创建环境实例, web环境使用StandardServletEnvironment, 非web环境使用StandardEnvironment
  ConfigurableEnvironment environment = getOrCreateEnvironment();
  //配置环境数据
  //1. **commandLineArgs**属性从启动参数中解析, 格式"--name=value"
  //2. 配置profiles. 有效的profile(通过**spring.profiles.active**配置) 和 通过SpringApplication.profiles()指定的额外profile
  configureEnvironment(environment, applicationArguments.getSourceArgs());
  //通过EventPublishingRunListener发布environmentPrepared事件
  listeners.environmentPrepared(environment);
  //如果是web环境, 将非web环境实例转换成web环境实例:
  //使用有效的profile配置和jndiProperties, servletConfigInitParams, servletContextInitParams的配置.
  if (isWebEnvironment(environment) && !this.webEnvironment) {
    environment = convertToStandardEnvironment(environment);
  }
  //输出banner
  if (this.bannerMode != Banner.Mode.OFF) {
    printBanner(environment);
  }

  //创建上下文对象, 没有指定实现类的话(使用SpringApplicationBuilder.contextClass), 使用默认context类. 然后通过反射实例化上下文对象.
  //1. web环境使用org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
  //2. org.springframework.context.annotation.AnnotationConfigApplicationContext
  
  //初始化实例的时候会做很多事,
  //1. 创建AnnotatedBeanDefinitionReader. 注册相关的Annotation Post Processor, 包括: ConfigurationClassPostProcessor(处理@Configuration标注的类), AutowiredAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, EventListenerMethodProcessor, DefaultEventListenerFactory
  //2. 创建ClassPathBeanDefinitionScanner. 扫描器, 扫描默认的过滤器@Service, @Component, @Registry, @Controller. 同时支持J2EE6的@ManagedBean和@Named
  // Create, load, refresh and run the ApplicationContext
  context = createApplicationContext();
  //设置环境
  context.setEnvironment(environment);
  //后续的处理
  postProcessApplicationContext(context);
  //应用初始化器(ApplicationContextInitializer的实现类), 对上下文对象做更多初始化的操作, 比如:
  //1. 添加BeanFactoryPostProcessor
  //2 .设置上下文对象id
  //3 .代理配置中context.initializer.classes指定的初始化类
  //4. 添加listener, 在web容器启动后更新环境变量中的端口号(server.ports中的local.server.port)
  applyInitializers(context);
  //通过EventPublishingRunListener发布contextPrepared事件
  listeners.contextPrepared(context);
  //打印启动信息和有效的profile信息
  if (this.logStartupInfo) {
    logStartupInfo(context.getParent() == null);
    logStartupProfileInfo(context);
  }

  //将ApplicationArguments实例注册到BeanFactory中, 名字为springApplicationArguments
  // Add boot specific singleton beans
  context.getBeanFactory().registerSingleton("springApplicationArguments",
      applicationArguments);

  //从source(可以是Resource, Package, CharSequence或者Class. 从run方法进来的为Class)类加载Bean到上下文对象中
  // Load the sources
  Set<Object> sources = getSources();
  Assert.notEmpty(sources, "Sources must not be empty");
  load(context, sources.toArray(new Object[sources.size()]));
  //通过EventPublishingRunListener发布contextLoaded事件
  listeners.contextLoaded(context);

  //更新上下文对象, 调用ApplicationContext.refresh()方法
  // Refresh the context
  refresh(context);
  if (this.registerShutdownHook) {
    try {
      context.registerShutdownHook();
    }
    catch (AccessControlException ex) {
      // Not allowed in some environments.
    }
  }
  return context;
}

更新上下文 ApplicationContext.refresh()

  1. prepareRefresh
    记录启动时间, 初始化上下文环境信息中的占位符, 检查必须的属性
  2. obtainFreshBeanFactory
    重建内置的BeanFactory, 并加载bean定义
  3. prepareBeanFactory
    初始化BeanFactory的标准上下文属性, 如BeanClassLoader, ExpressionResolver, PropertyEditorRegistrar, BeanPostProcessor, LoadTimeWeaverAwarePostProcessor等等.
  4. postProcessBeanFactory
    标准初始化后修改上下文内置的BeanFactory
  5. invokeBeanFactoryPostProcessors
    实例化并调用注册的 BeanFactoryPostProcessor , 基于精确的顺序如果指定了顺序的话.
    有些processor是操作Bean定义注册表的(如 @Configuration 标注的类bean包含其他的bean定义), 会在常规的 BeanFactoryPostProcessor 的检查发生之前.
    在上下文对象的bean定义注册器进行了标准初始化之后进, 所有的常规bean定义都已经被加载了, 但是还没有bean被实例化. 在post-processiong之前可以添加更多的bean定义. @Configuration 标注的类中的bean定义会在此时假如到注册器中 .
  6. registerBeanPostProcessors
    实例化并调用注册的 BeanPostProcessor , 如果有顺序的话, 按照顺序来调用.
  7. initMessageSource
    初始化名为 messageSourceMessageSource 实例.
  8. initApplicationEventMulticaster
    初始化名为 applicationEventMulticasterApplicationEventMulticaster 实例, 应用可以用来注册应用事件的监听.
  9. onRefresh
    供子类实现添加更多的更新操作.
  10. registerListeners
    通过 applicationEventMulticaster 注册 ApplicationListener 实现类的监听器.
  11. finishBeanFactoryInitialization
    进行上下文的BeanFactory初始化的收尾. 如提前初始化 LoadTimeWeaverAware 的bean, 冻结配置禁止修改bean定义, 实例化non-lazy-init的bean.
  12. finishRefresh
    完成更新, 调用 LifecycleProcessor.onRefresh() , 发布 ContextRefreshedEvent 事件, 将上下文实例暴露在MBean中.

ConfigurationClassPostProcessor

BeanFactoryPostProcessor 的实现类, 用于引导 @Configuration 类.

默认情况下通过使用 <context:annotation-config/> 或者 <context:component-scan/> 注册.

注解

@SpringBootApplication

集合了 @Configuration , @EnableAutoConfiguration@ComponentScan
属性: exclude , excludeName , scanBasePackage , scanBasePackageClass

@Configuration

类似旧版配置中的xml配置文件, 提供Bean的定义和引入其他xml配置. 分别通过 @Bean@Import 实现.

在ApplicationContext.refresh()时是用 ConfigurationClassPostProcessor 进行bean的实例化.

可以与 @PropertySource , @Autowired , @Value , @Profile 搭配使用.

@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig{
    @Value("${bean.name}") String beanName;
    @Autowired DataSource dataSource;
    @Bean
    public MyBean myBean(){
        return new MyBean(beanName);
    }
    @Configuration
    @Profile("test")
    static class DatabaseConfigTest{
        @Bean
        DataSourcedataSource(){
            return new EmbeddedDatabaseBuilder().build();
        }
    }
    @Configuration
    @Profile("production")
    static class DatabaseConfigProduction{
        @Bean
        DataSourcedataSource(){
            return new EmbeddedDatabaseBuilder().build();
        }
    }
}

@EnableAutoConfiguration

开启Spring上下文对象的自动配置功能, 尝试去猜测和实例化你 可能需要的 bean.

这个功能是基于classPath来完成的. 比如: 项目中引用了 tomcat-embedded.jar , 你可能需要一个 TomcatEmbeddedServletContainerFactory 实例, 除非定义了自己的 EmbeddedServletContainerFactory 实例.

@ComponentScan

扫描使用 @Configuration 标注的类, 类似于Spring XML的 <context:component-scan> 元素.

使用 basePackagesbasePackageClasses 属性来指定要扫描的包, 如果没有指定, 则默认从使用了该注解的类的包开始扫描.

@Import

提示 @Configuration 有更多的类需要引入, 类似xml中的 <import> 标签.

可以引入 @Configuration 类, ImportSelector 的实现类和 ImportBeanDefinitionRegistrar 的实现类, 还有常规的 Component 类.

三者的处理方式不一样:

  • @Configuration 常规方式
  • ImportSelector 会根据泛型类型从 spring.factories 找到对应的配置类.
  • ImportBeanDefinitionRegistrar 可以实现在bean definition级别的处理 ( @Bean 实例级别)

引入 @Configuration 类中使用 @Bean 标注的实例, 可以通过 @Autowired 注入. Bean和声明Bean的Configuration类本身都可以通过 @Autowired 注入.

引入XML或者非Configuration, 使用 @ImportResource .

原文  http://atbug.com/glance-over-spring-boot-source/
正文到此结束
Loading...