springboot源码解析

作者: 笔记本一号 | 来源:发表于2022-07-30 12:30 被阅读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的部分内容:

    # Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
    org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
    
    # Application Listeners
    org.springframework.context.ApplicationListener=\
    org.springframework.boot.autoconfigure.BackgroundPreinitializer
    

    2、执行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 Configure
    org.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,\
    

    相关文章

      网友评论

        本文标题:springboot源码解析

        本文链接:https://www.haomeiwen.com/subject/ukgcwrtx.html