springboot源码分析(1) 启动过程类 war jar 支持 及其源码分析

springboot启动相关配置

启动类

集成SpringBootServletInitializer

@SpringBootApplication
public class AppApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        SpringApplicationBuilder springApplicationBuilder = builder.sources(AppApplication.class);
        return  springApplicationBuilder;
    }
}

springboot依赖调整

在spring-boot-starter-web中去掉tomcat 依赖jar包。同时在依赖spring-boot-starter-tomcat 并将其scope设置为provided。这样做的好处是 这个启动类在开发过程中 idea等开发工具依然可以使用main方法进行启动,在maven打包的时候可以直接打包设置为war

        
            org.springframework.boot
            spring-boot-starter-web
            
                
                    org.springframework.boot
                    spring-boot-starter-tomcat
                
            
        
        
            org.springframework.boot
            spring-boot-starter-tomcat
            provided
        

springboot源码分析

jar包启动 SpringApplication 构造ConfigurableApplicationContext

调用run方法 会最终调用到return new SpringApplication(primarySources).run(args);

    public static ConfigurableApplicationContext run(Class primarySource,
            String... args) {
        return run(new Class[] { primarySource }, args);
    }

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

new SpringApplication(primarySources) 设置初始化程序 设置监听

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

ApplicationContextInitializer 应用程序初始化

public interface ApplicationContextInitializer {

    /**
     * Initialize the given application context.
     * @param applicationContext the application to configure
     */
    void initialize(C applicationContext);

}

初始化程序会在org.springframework.boot:spring-boot:2.1.3Release下找到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.web.context.ServerPortInfoApplicationContextInitializer

ApplicationListener应用程序监听

public interface ApplicationListener extends EventListener {
    void onApplicationEvent(E event);
}

在springspring.factories文件中。找到对应的初始化对应的监听类

# 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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

监听类会在在springboot程序启动的过程中对应相应的event,将事件进行广播。这里是一个观察者模式。

ConfigurableApplicationContext run

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection 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();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

打印banner图片 应用程序可以自定义默认为springboot
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
重点关注方法:这里会创建容器
context = createApplicationContext();
将环境 监听 等参数设置进入容器 会加载配置文件的中 spring.profiles.active=local 参数来获取当前环境。并在后续加载配置文件过程中 加载 application-local.properties 文件

protected void configureEnvironment(ConfigurableEnvironment environment,
            String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService
                    .getSharedInstance();
            environment.setConversionService(
                    (ConfigurableConversionService) conversionService);
        }
        configurePropertySources(environment, args);
        configureProfiles(environment, args);
    }

configureIgnoreBeanInfo 对spring.beaninfo.ignore 支持

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
        if (System.getProperty(
                CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
            Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
                    Boolean.class, Boolean.TRUE);
            System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
                    ignore.toString());
        }
    }

prepareContext 准备容器需要相关的参数

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        postProcessApplicationContext(context);
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // Load the sources
        Set sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }

postProcessApplicationContext 创建容器后的回调

//刷新容器
refreshContext(context);
最终会调用spring-contextjar包中的refresh代码 与spring源码分析一致

protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

启动过程。调用完成。在下一章节分析refresh bean扫描过程

你可能感兴趣的:(springboot源码分析(1) 启动过程类 war jar 支持 及其源码分析)