springboot源码分析

计算机软件开发 2024-9-7 08:00:15 117 0 来自 中国
1、初始化SpringApplication

启动的第一步,先调用SpringApplication的静态函数run方法,run方法会调用SpringApplication的有参构造方法来初始化SpringApplication。
而SpringApplication的初始化方法重要做以下几件事变:
1、推断当前 WEB 应用范例,一共有三种:
NONE:无内嵌的web容器启动,这种模式springboot须要运行于外部的web容器中
SERVLET:利用内嵌的web容器启动
REACTIVE:利用spring5的新特性,相应式启动

2、从META-INF/spring.factories读取对应的ApplicationContextInitializer的类装配到聚会合并去重
3、从META-INF/spring.factories读取对应ApplicationListener的类装配到聚会合并去重*
SpringApplication的构造函数实例化了 初始化上下文的各种接口ApplicationContextInitializer以及监听器ApplicationListener,要留意的是这里的实例化,并不像平时的Spring Components一样通过注解和扫包完成,而是通过一种不依赖Spring上下文的加载方法,如许才气在Spring完成启动前做各种设置。Spring的办理方法是以接口的全限定名作为key,实现类的全限定名作为value记载在项目的META-INF/spring.factories文件中,然后通过SpringFactoriesLoader工具类提供静态方法举行类加载并缓存下来,spring.factories是Spring Boot的焦点设置文件,目的是帮助Spring Boot完成主动扮装配。
public static void main(String[] args) {        SpringApplication.run(DemoApplication.class, args);    }public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {       .........................................        //推断当前 WEB 应用范例        this.webApplicationType = WebApplicationType.deduceFromClasspath();        //从"META-INF/spring.factories"读取对应的ApplicationContextInitializer类的装配到聚会合并去重        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));        //从"META-INF/spring.factories"读取对应ApplicationListener类的装配到聚会合并去重        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));        //获取Main方法地点类,并赋值给mainApplicationClass        this.mainApplicationClass = this.deduceMainApplicationClass();    }spring.factories的部分内容:
# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.autoconfigure.BackgroundPreinitializer2、实行SpringApplication.run启动容器

启动的步调重要是以下几个步调:
1、stopWatch.start():记载容器启动淹灭的时间
2、this.getRunListeners(args):从"META-INF/spring.factories"获取key为SpringApplicationRunListener的运行时监听器,着实就是EventPublishingRunListener监听器
3、listeners.starting() 向运行时监听器注册监听事故
4、ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments)根据监听器准备spring容器的情况变量
5、context = this.createApplicationContext()根据WEB 应用范例创建相应的容器,一共有三种:
NONE:AnnotationConfigApplicationContext
SERVLET:AnnotationConfigServletWebServerApplicationContext
REACTIVE:AnnotationConfigReactiveWebServerApplicationContext

6、this.prepareContext(context, environment, listeners, applicationArguments, printedBanner)这里重要是给容器设置前面准备好的情况变量,而且实行之前在spring.factories中读取的ApplicationContextInitializer类的initialize方法
7、this.refreshContext(context)革新容器,这里比力重点反面单独分析
8、this.afterRefresh(context, applicationArguments)这里是空的方法,用于子类继续做一些容器启动后的拓展
9、监听器发布ApplicationStartedEvent事故和ApplicationReadyEvent事故
public ConfigurableApplicationContext run(String... args) {        StopWatch stopWatch = new StopWatch();        //记载容器启动淹灭的时间        stopWatch.start();        ConfigurableApplicationContext context = null;        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();        this.configureHeadlessProperty();        //从"META-INF/spring.factories"获取key为SpringApplicationRunListener的监听器,着实就是EventPublishingRunListener监听器        SpringApplicationRunListeners listeners = this.getRunListeners(args);        //遍历并聚会合的监听器,并注册须要监听事故        listeners.starting();        Collection exceptionReporters;        try {            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);           //准备spring容器的情况变量                        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);            this.configureIgnoreBeanInfo(environment);            Banner printedBanner = this.printBanner(environment);           //根据WEB 应用范例创建相应的容器            context = this.createApplicationContext();            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);             //这里重要是给容器设置前面准备好的情况变量,而且实行之前在spring.factories中读取的ApplicationContextInitializer类的initialize方法            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);           //革新容器            this.refreshContext(context);           //这里是空的方法,用于子类继续做一些容器启动后的拓展            this.afterRefresh(context, applicationArguments);            stopWatch.stop();            if (this.logStartupInfo) {                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);            }            //监听器发布ApplicationStartedEvent事故            listeners.started(context);          try {            listeners.running(context);//发布ApplicationReadyEvent事故           }         ......................................//返回容器上下文    return context;    }private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {        context.setEnvironment(environment);        this.postProcessApplicationContext(context);        this.applyInitializers(context);        listeners.contextPrepared(context);        ......................................    }3、refresh()革新容器

1、prepareRefresh()容器的预处理惩罚:记载启动时间,设置容器的状态,预留钩子方法给子类做属性设置,保存早期监听事故
2、obtainFreshBeanFactory()获取DefaultListableBeanFactory的作为工厂对象
3、prepareBeanFactory(beanFactory)设置工厂对象的属性,包罗:类加载器、表达式分析器、添加后置处理惩罚器ApplicationContextAwareProcessor,体系情况属性Environment等
4、postProcessBeanFactory(beanFactory)钩子方法,预留给子类实现,在工厂对象准备革新容器前做一些处理惩罚
5、invokeBeanFactoryPostProcessors(beanFactory)获取BeanDefinitionRegistryPostProcessor,遍历并根据优先级(继续order接口)实行其后置方法postProcessBeanDefinitionRegistry()方法。然后在获取全部的BeanFactoryPostProcessor的,再遍历并根据优先级(继续order接口)实行后置方法postProcessBeanFactory(),由此可见后置处理惩罚器BeanDefinitionRegistryPostProcessor是在BeanFactoryPostProcessor之前实行
6、registerBeanPostProcessors(beanFactory)获取全部的BeanPostProcessor,比方:InstantiationAwareBeanPostProcessor等,根据优先级(继续order接口)将全部的BeanPostProcessor注册到工厂对象中
7、initMessageSource()举行国际化
8、initApplicationEventMulticaster() 初始化的事故派发器
9、onRefresh()钩子方法,预留给子类举行拓展处理惩罚,其中springboot的web容器AnnotationConfigServletWebServerApplicationContext会在这里启动Tomcat
10、registerListeners()注册事故监听器,监听器须要实现 ApplicationListener 接口
11、finishBeanFactoryInitialization(beanFactory)初始化全部的单实例bean,重要方法在工厂对象的preInstantiateSingletons()方法,先获取RootBeanBefinition,在判定是否是factoryBean,是则调用factoryBean的方法创建bean,不是则调用getBean()方法举行bean的创建,getBean()方法是spring创建bean的焦点类,我之前在spring源码分析那里分析过,这里不再赘述,重要流程就先从缓存中获取bean,获取不到就重新开始创建bean,并颠末bean的实例化、属性赋值、初始化的生命周期,中央调用Aware类的方法和上面注册的BeanPostProcessor的前后置方法,完成IOC创建
12、finishRefresh()容器调用LifecycleProcessor生命周期处理惩罚器的onRefresh()和onClose()方法,然后调用publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)))发布容器革新完成事故
public void refresh() throws BeansException, IllegalStateException {        synchronized(this.startupShutdownMonitor) {            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");            this.prepareRefresh();            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();            this.prepareBeanFactory(beanFactory);            try {                this.postProcessBeanFactory(beanFactory);                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");                this.invokeBeanFactoryPostProcessors(beanFactory);                this.registerBeanPostProcessors(beanFactory);                beanPostProcess.end();                this.initMessageSource();                this.initApplicationEventMulticaster();                this.onRefresh();                this.registerListeners();                this.finishBeanFactoryInitialization(beanFactory);                this.finishRefresh();            } catch (BeansException var10) {                if (this.logger.isWarnEnabled()) {                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);                }                this.destroyBeans();                this.cancelRefresh(var10);                throw var10;            } finally {                this.resetCommonCaches();                contextRefresh.end();            }        }    }protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {        .......................................        beanFactory.preInstantiateSingletons();    }public void preInstantiateSingletons() throws BeansException {        List<String> beanNames = new ArrayList(this.beanDefinitionNames);        Iterator var2 = beanNames.iterator();        while(true) {            String beanName;            Object bean;            do {                while(true) {                    RootBeanDefinition bd;                    do {                        do {                           do {                                if (!var2.hasNext()) {                                    var2 = beanNames.iterator();                                    while(var2.hasNext()) {                                        beanName = (String)var2.next();                                        Object singletonInstance = this.getSingleton(beanName);                                        if (singletonInstance instanceof SmartInitializingSingleton) {                                            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;                                            if (System.getSecurityManager() != null) {                                                AccessController.doPrivileged(() -> {                                                    smartSingleton.afterSingletonsInstantiated();                                                    return null;                                                }, this.getAccessControlContext());                                            } else {                                                smartSingleton.afterSingletonsInstantiated();                                            }                                        }                                    }                                    return;                                }                                beanName = (String)var2.next();                                bd = this.getMergedLocalBeanDefinition(beanName);                            } while(bd.isAbstract());                        } while(!bd.isSingleton());                    } while(bd.isLazyInit());                    if (this.isFactoryBean(beanName)) {                        bean = this.getBean("&" + beanName);                        break;                    }                    this.getBean(beanName);                }            } while(!(bean instanceof FactoryBean));            FactoryBean<?> factory = (FactoryBean)bean;            boolean isEagerInit;            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {                SmartFactoryBean var10000 = (SmartFactoryBean)factory;                ((SmartFactoryBean)factory).getClass();                isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());            } else {                isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();            }            if (isEagerInit) {                this.getBean(beanName);            }        }    }4、springboot的主动扮装配

@SpringBootApplication上的注解@EnableAutoConfiguration,通过@Import({AutoConfigurationImportSelector.class})注入AutoConfigurationImportSelector,AutoConfigurationImportSelector通过调用getAutoConfigurationEntry方法,方法中会调用getCandidateConfigurations方法,然后通过SpringFactoriesLoader.loadFactoryNames方法,从META-INF/spring.factories读取EnableAutoConfiguration的类为key,value为须要主动装配的xxxConfiguration设置类的数组,通过SpringFactoriesLoader机制创建对应的bean,注入到容器中,完成了主动装配。
这原来须要在spring的xml设置文件中去设置bean的操纵就免除了 ,也就是说我们可以事先在xxxConfiguration中做好各种默认设置,然后通过加入到spring.factories中让spring主动读取并装配,实现了starter默认设置到达了约定大于设置的头脑,这就是也就是springboot的主动装配
简朴的流程如下:@EnableAutoConfiguration->@Import({AutoConfigurationImportSelector.class})->SpringFactoriesLoader.loadFactoryNames->META-INF/spring.factories->org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxConfiguration,xxxConfiguration....
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration {    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";    Class<?>[] exclude() default {};    String[] excludeName() default {};}AutoConfigurationImportSelector类及对应的SpringFactoriesLoader.loadFactoryNames及SpringFactoriesLoader.loadSpringFactories方法
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {     protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {        if (!this.isEnabled(annotationMetadata)) {            return EMPTY_ENTRY;        } else {            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);            configurations = this.removeDuplicates(configurations);            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);            this.checkExcludedClasses(configurations, exclusions);            configurations.removeAll(exclusions);            configurations = this.getConfigurationClassFilter().filter(configurations);            this.fireAutoConfigurationImportEvents(configurations, exclusions);            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);        }    }protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");        return configurations;    }}public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {        String factoryTypeName = factoryType.getName();        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());    }    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);        if (result != null) {            return result;        } else {            try {                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");                LinkedMultiValueMap result = new LinkedMultiValueMap();                while(urls.hasMoreElements()) {                    URL url = (URL)urls.nextElement();                    UrlResource resource = new UrlResource(url);                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);                    Iterator var6 = properties.entrySet().iterator();                    while(var6.hasNext()) {                        Entry<?, ?> entry = (Entry)var6.next();                        String factoryTypeName = ((String)entry.getKey()).trim();                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());                        int var10 = var9.length;                        for(int var11 = 0; var11 < var10; ++var11) {                            String factoryImplementationName = var9[var11];                            result.add(factoryTypeName, factoryImplementationName.trim());                        }                    }                }                cache.put(classLoader, result);                return result;            } catch (IOException var13) {                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);            }        }    }# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-23 19:35, Processed in 0.161249 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表