springboot启动配置原理

springboot启动流程

1.创建springApplication对象

        @SuppressWarnings({ "unchecked", "rawtypes" })
        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();
            //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
            setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
            //从类路径下找到META-INF/spring.factories配置的所有 ApplicationListener,然后保存起来
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            //推断主配置类
            this.mainApplicationClass = deduceMainApplicationClass();
        }

2.运行run方法

	public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        //从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListeners
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            //封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //准备环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            //打印banner
            Banner printedBanner = printBanner(environment);
            //创建IOC容器,决定创建的是web的IOC还是普通的IOC
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            //准备上下文,回调所有的ApplicationContextInitializer的initialize方法,所有的SpringApplicationRunListener的contextPrepared方法
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //刷新容器,IOC容器初始化,所有的单实例bean初始化,如果是web应用,还会创建嵌入式的Tomcat
            //扫描,创建,加载所有的组件
            refreshContext(context);
            //从IOC容器中获取所有的ApplicationRunner和CommandLineRunner,分别进行回调
            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;
    }

springboot启动事件

几个重要的事件回调机制

ApplicationContextInitializer  配置在META-INF/spring.factories中
SpringApplicationRunListener   配置在META-INF/spring.factories中
ApplicationRunner              放在IOC容器中
CommandLineRunner              放在IOC容器中 

springboot自动配置原理

1.springboot在启动时加载主配置类,开启了自动配置功能 @EnableAutoConfiguration     
2.@EnableAutoConfiguration 作用:
        利用EnableAutoConfigurationImportSelector给容器导入一些组件
        可以查看selectImports()方法的内容
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
SpringFactoriesLoader.loadFactoryNames()
扫描所有jar包类路径下 META-INF/spring.factories中的内容
把扫描到的这些文件的内容包装成properties对象
从properties中获取到EnabAutoConfiguration.class对应的值,然后把它们添加到容器中

每一个XXXAutoConfiguration都是容器的一个组件,都加入到容器中,用它们来做自动配置

3.每一个自动配置类进行自动配置功能

4.以 HttpEncodingAutoConfiguration 为例解释自动配置功能  
@Configuration(proxyBeanMethods = false)    //表示这是一个配置类
@EnableConfigurationProperties(HttpProperties.class)    //启动指定类的ConfigurationProperties功能
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) //根据不同的条件,如果满足指定的条件,整个配置类才会生效
@ConditionalOnClass(CharacterEncodingFilter.class)  //判断当前项目中有没有CharacterEncodingFilter,如果有,才会生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)//判断配置文件中是否存在某个配置 spring.http.encoding.enabled,matchIfMissing = true表示即使没有配置,也可以生效
public class HttpEncodingAutoConfiguration  

根据当前不同的条件判断,决定这个配置类是否生效,一旦生效,使用@Bean给容器中添加一个组件

@Bean   //给容器中添加一个组件
@ConditionalOnMissingBean   //在不存在该Bean的情况下添加
public CharacterEncodingFilter characterEncodingFilter() {
	CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
	filter.setEncoding(this.properties.getCharset().name());
	filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); 
	filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
	return filter;
}

5.所有在配置文件中能配置的属性都是在XXProperties中封装着,配置文件能配置什么就可以参考这个类中的属性
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties
posted @ 2022-07-22 14:13  Chen_Ken  阅读(184)  评论(0)    收藏  举报