spring到底是什么_Spring Web Flow

(1) 2024-09-15 20:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
spring到底是什么_Spring Web Flow,希望能够帮助你!!!。

大家好,这篇文章跟大家来聊下 Spring 中提供的常用扩展点、Spring SPI 机制、以及 SpringBoot 自动装配原理,重点介绍下 Spring 基于这些扩展点怎么跟配置中心(Apollo、Nacos、Zookeeper、Consul)等做集成。

写在前面

我们大多数 Java 程序员的日常工作基本都是在做业务开发,俗称 crudboy。

作为 crudboy 的你有没有这些烦恼呢?

  1. 随着业务的迭代,新功能的加入,代码变得越来越臃肿,可维护性越来越低,慢慢变成了屎山
  2. 遇到一些框架层的问题不知道怎么解决
  3. 面试被问到使用的框架、中间件原理、源码层东西,不知道怎么回答
  4. 写了 5 年代码了,感觉自己的技术没有理想的长进

如果你有上述这些烦恼,我想看优秀框架的源码会是一个很好的提升方式。通过看源码,我们能学到业界大佬们优秀的设计理念、编码风格、设计模式的使用、高效数据结构算法的使用、魔鬼细节的巧妙应用等等。这些东西都是助力我们成为一个优秀工程师不可或缺的。

如果你打算要看源码了,优先推荐 Spring、Netty、Mybatis、JUC 包。

Spring 扩展

我们知道 Spring 提供了很多的扩展点,第三方框架整合 Spring 其实大多也都是基于这些扩展点来做的。所以熟练的掌握 Spring 扩展能让我们在阅读源码的时候能快速的找到入口,然后断点调试,一步步深入框架内核。

这些扩展包括但不限于以下接口:

BeanFactoryPostProcessor:在 Bean 实例化之前对 BeanDefinition 进行修改

BeanPostProcessor:在 Bean 初始化前后对 Bean 进行一些修改包装增强,比如返回代理对象

Aware:一个标记接口,实现该接口及子接口的类会收到 Spring 的通知回调,赋予某种 Spring 框架的能力,比如 ApplicationContextAware、EnvironmentAware 等

ApplicationContextInitializer:在上下文准备阶段,容器刷新之前做一些初始化工作,比如我们常用的配置中心 client 基本都是继承该初始化器,在容器刷新前将配置从远程拉到本地,然后封装成 PropertySource 放到 Environment 中供使用

ApplicationListener:Spring 事件机制,监听特定的应用事件(ApplicationEvent),观察者模式的一种实现

FactoryBean:用来自定义 Bean 的创建逻辑(Mybatis、Feign 等等)

ImportBeanDefinitionRegistrar:定义@EnableXXX 注解,在注解上 Import 了一个 ImportBeanDefinitionRegistrar,实现注册 BeanDefinition 到容器中

InitializingBean:在 Bean 初始化时会调用执行一些初始化逻辑

ApplicationRunner/CommandLineRunner:容器启动后回调,执行一些初始化工作

上述列出了几个比较常用的接口,但是 Spring 扩展远不于此,还有很多扩展接口大家可以自己去了解。

Spring SPI 机制

在讲接下来内容之前,我们先说下 Spring 中的 SPI 机制。Spring 中的 SPI 主要是利用 META-INF/spring.factories 文件来实现的,文件内容由多个 k = list(v) 的格式组成,比如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.dtp.starter.adapter.dubbo.autoconfigure.ApacheDubboTpAutoConfiguration,\ com.dtp.starter.adapter.dubbo.autoconfigure.AlibabaDubboTpAutoConfiguration org.springframework.boot.env.EnvironmentPostProcessor=\ com.dtp.starter.zookeeper.autoconfigure.ZkConfigEnvironmentProcessor 复制代码

这些 spring.factories 文件可能是位于多个 jar 包中,Spring 容器启动时会通过 ClassLoader.getResources() 获取这些 spring.factories 文件的全路径。然后遍历路径以字节流的形式读取所有的 k = list(v) 封装到到一个 Map 中,key 为接口全限定类名,value 为所有实现类的全限定类名列表。

上述说的这些加载操作都封装在 SpringFactoriesLoader 类里。该类很简单,提供三个加载方法、一个实例化方法,还有一个 cache 属性,首次加载到的数据会保存在 cache 里,供后续使用。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第1张

SpringBoot 核心要点

上面讲的 SPI 其实就是我们 SpringBoot 自动装配的核心。

何为自动装配?

自动装配对应的就是手动装配,在没 SpringBoot 之前,我们使用 Spring 就是用的手动装配模式。在使用某项第三方功能时,我们需要引入该功能依赖的所有包,并测试保证这些引入包版本兼容。然后在 XML 文件里进行大量标签配置,非常繁琐。后来 Spring4 里引入了 JavaConfig 功能,利用 @Configuration + @Bean 来代替 XML 配置,虽然对开发来说是友好了许多,但是这些模板式配置代码还是很繁琐,会浪费大量时间做配置。Java 重可能也就是这个时候给人留的一种印象。

在该背景下出现了 SpringBoot,SpringBoot 可以说是稳住了 Java 的地位。SpringBoot 提供了自动装配功能,自动装配简单来说就是将某种功能(如 web 相关、redis 相关、logging 相关等)打包在一起,统一管理依赖包版本,并且约定好相关功能 Bean 的装配规则,使用者只需引入一个依赖,通过少量注解或简单配置就可以使用第三方组件提供的功能了。

在 SpringBoot 中这类功能组件有一个好听的名字叫做 starter。比如 spring-boot-starter-web、spring-boot-starter-data-redis、spring-boot-starter-logging 等。starter 里会通过 @Configuration + @Bean + @ConditionalOnXXX 等注解定义要注入 Spring 中的 Bean,然后在 spring.factories 文件中配置为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的实现,就可以完成自动装配了。

具体装配流程怎么样的呢?

其实也很简单,基本都是 Spring 中的知识,没啥新颖的。主要依托于@EnableAutoConfiguration 注解,该注解上会 Import 一个 AutoConfigurationImportSelector,看下继承关系,该类继承于 DeferredImportSelector。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第2张

主要方法为 getAutoConfigurationEntry()

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { // 1 if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); // 2 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); // 3 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); // 4 configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } 复制代码

方法解读

  1. 通过 spring.boot.enableautoconfiguration 配置项判断是否启用自动装配,默认为 true
  2. 使用上述说的 SpringFactoriesLoader.loadFactoryNames() 加载所有 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的实现类的全限定类名,借助 HashSet 进行去重
  3. 获取 @EnableAutoConfiguration 注解上配置的要 exclude 的类,然后排除这些特定类
  4. 通过 @ConditionalOnXXX 进行过滤,满足条件的类才会留下,封装到 AutoConfigurationEntry 里返回

那 getAutoConfigurationEntry() 方法在哪儿调用呢?

public void refresh() throws BeansException, IllegalStateException { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } 复制代码

以上是 Spring 容器刷新时的几个关键步骤,在步骤二 invokeBeanFactoryPostProcessors() 中会调用所有已经注册的 BeanFactoryPostProcessor 进行处理。此处调用也是有顺序的,优先会调用所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(),BeanDefinitionRegistryPostProcessor 是一个特殊的 BeanFactoryPostProcessor,然后再调用所有 BeanFactoryPostProcessor#postProcessBeanFactory()。

ConfigurationClassPostProcessor 是 BeanDefinitionRegistryPostProcessor 的一个实现类,该类主要用来处理 @Configuration 注解标注的类。我们用 @Configuration 标注的类会被 ConfigurationClassParser 解析包装成 ConfigurationClass 对象,然后再调用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass() 进行 BeanDefination 的注册。

其中 ConfigurationClassParser 解析时会递归处理源配置类上的注解(@PropertySource、@ComponentScan、@Import、@ImportResource)、 @Bean 标注的方法、接口上的 default 方法,进行 ConfigurationClass 类的补全填充,同时如果该配置类有父类,同样会递归进行处理。具体代码请看 ConfigurationClassParser#doProcessConfigurationClass() 方法

protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { // Process any @PropertySource annotations // Process any @ComponentScan annotations // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // Process any @ImportResource annotations // Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null; } 复制代码

1)parser.parse(candidates) 解析得到完整的 ConfigurationClass 对象,主要填充下图框中的四部分。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第3张

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第4张

2)this.reader.loadBeanDefinitions(configClasses) 根据框中的四部分进行 BeanDefination 的注册。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第5张

在上述 processImports() 过程中会将 DeferredImportSelector 的实现类放在 deferredImportSelectorHandler 中以便延迟到所有的解析工作完成后进行处理。deferredImportSelectorHandler 中就存放了 AutoConfigurationImportSelector 类的实例。process() 方法里经过几步走会调用到 AutoConfigurationImportSelector#getAutoConfigurationEntry() 方法上获取到自动装配需要的类,然后进行与上述同样的 ConfigurationClass 解析封装工作。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第6张

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第7张

代码层次太深,调用太复杂,建议自己断点调试源码跟一遍印象会更深刻。

ApplicationContextInitializer 调用时机

我们就以 SpringBoot 项目为例来看,在 SpringApplication 的构造函数中会进行 ApplicationContextInitializer 的初始化。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第8张

上图中的 getSpringFactoriesInstances 方法内部其实就是调用 SpringFactoriesLoader.loadFactoryNames 获取所有 ApplicationContextInitializer 接口的实现类,然后反射创建对象,并对这些对象进行排序(实现了 Ordered 接口或者加了 @Order 注解)。

 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } 复制代码

至此,项目中所有 ApplicationContextInitializer 的实现已经加载并且创建好了。在 prepareContext 阶段会进行所有已注册的 ApplicationContextInitializer#initialize() 方法的调用。在此之前prepareEnvironment 阶段已经准备好了环境信息,此处接入配置中心就可以拉到远程配置信息然后填充到 Spring 环境中供应用使用。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第9张

SpringBoot 集成 Apollo

ApolloApplicationContextInitializer 实现 ApplicationContextInitializer 接口,并且在 spring.factories 文件中配置如下

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第10张

org.springframework.context.ApplicationContextInitializer=\ com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer 复制代码

initialize() 方法中会根据 apollo.bootstrap.namespaces 配置的 namespaces 进行配置的拉去,拉去到的配置会封装成 ConfigPropertySource 添加到 Spring 环境 ConfigurableEnvironment 中。具体的拉去流程就不展开讲了,感兴趣的可以自己去阅读源码了解。

SpringCloud 集成 Nacos、Zk、Consul

在 SpringCloud 场景下,SpringCloud 规范中提供了 PropertySourceBootstrapConfiguration 继承 ApplicationContextInitializer,另外还提供了个 PropertySourceLocator,二者配合完成配置中心的接入。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第11张

initialize 方法根据注入的 PropertySourceLocator 进行配置的定位获取,获取到的配置封装成 PropertySource 对象,然后添加到 Spring 环境 Environment 中。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第12张

Nacos、Zookeeper、Consul 都有提供相应 PropertySourceLocator 的实现

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第13张

我们来分析下 Nacos 提供的 NacosPropertySourceLocator,locate 方法只提取了主要流程代码,可以看到 Nacos 启动会加载以下三种配置文件,也就是我们在 bootstrap.yml 文件里配置的扩展配置 extension-configs、共享配置 shared-configs 以及应用自己的配置,加载到配置文件后会封装成 NacosPropertySource 放到 Spring 的 Environment 中。

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第14张

public PropertySource<?> locate(Environment env) { loadSharedConfiguration(composite); loadExtConfiguration(composite); loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); return composite; } 复制代码

loadApplicationConfiguration 加载应用配置时,同时会加载以下三种配置,分别是

不带扩展名后缀,application

带扩展名后缀,application.yml

带环境,带扩展名后缀,application-prod.yml

并且从上到下,优先级依次增高

private void loadApplicationConfiguration( CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) { String fileExtension = properties.getFileExtension(); String nacosGroup = properties.getGroup(); // load directly once by default loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true); // load with suffix, which have a higher priority than the default loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true); // Loaded with profile, which have a higher priority than the suffix for (String profile : environment.getActiveProfiles()) { String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension; loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true); } } 复制代码

加载过程中,通过 namespace, dataId, group 唯一定位一个配置文件

首先获取本地缓存的配置,如果有直接返回

如果步骤1从本地没找到相应配置文件,开始从远处拉去,Nacos 2.0 以上版本使用 Grpc 协议进行远程通信,1.0 及以下使用 Http 协议进行远程通信

对拉去到的字符串进行解析,封装成 NacosPropertySource 返回

具体细节就不展开讲了,可以自己看源码了解

Zookeeper、Consul 的接入也是非常简单,可以自己分析一遍。如果我们有自研的配置中心,需要在 SpringCloud 环境下使用,可以根据 SpringCloud 提供的这些扩展参考以上几种实现快速的写个 starter 进行接入。

Spring的设计

在上一步,我们实现了自己的方案,并基于一些设想进行了扩展性优化,现在,我们就来认识一下实际上Spring的设计

那么,在Spring中又是由哪些"角色"构成的呢?

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第15张

1、Bean: Spring作为一个IoC容器,最重要的当然是Bean咯

2、BeanFactory: 生产与管理Bean的工厂

3、BeanDefinition: Bean的定义,也就是我们方案中的Class,Spring对它进行了封装

4、BeanDefinitionRegistry: 类似于Bean与BeanFactory的关系,BeanDefinitionRegistry用于管理BeanDefinition

5、BeanDefinitionRegistryPostProcessor: 用于在解析配置类时的处理器,类似于我们方案中的ClassProcessor

6、BeanFactoryPostProcessor: BeanDefinitionRegistryPostProcessor父类,让我们可以再解析配置类之后进行后置处理

7、BeanPostProcessor: Bean的后置处理器,用于在生产Bean的过程中进行一些处理,比如依赖注入,类似我们的AutowiredAnnotationBeanProcessor

8、ApplicationContext: 如果说以上的角色都是在工厂中生产Bean的工人,那么ApplicationContext就是我们Spring的门面,ApplicationContext与BeanFactory是一种组合的关系,所以它完全扩展了BeanFactory的功能,并在其基础上添加了更多特定于企业的功能,比如我们熟知的ApplicationListener(事件监听器)

以上说的类似其实有一些本末倒置了,因为实际上应该是我们方案中的实现类似于Spring中的实现,这样说只是为了让大家更好的理解

我们在经历了自己方案的设计与优化后,对这些角色其实是非常容易理解的

接下来,我们就一个一个的详细了解一下

BeanFactory

BeanFactory是Spring中的一个顶级接口,它定义了获取Bean的方式,Spring中还有另一个接口叫SingletonBeanRegistry,它定义的是操作单例Bean的方式,这里我将这两个放在一起进行介绍,因为它们大体相同,SingletonBeanRegistry的注释上也写了可以与BeanFactory接口一起实现,方便统一管理。

BeanFactory

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第16张

1、ListableBeanFactory:接口,定义了获取Bean/BeanDefinition列表相关的方法,如getBeansOfType(Class type)

2、AutowireCapableBeanFactory:接口,定义了Bean生命周期相关的方法,如创建bean, 依赖注入,初始化

3、AbstractBeanFactory:抽象类,基本上实现了所有有关Bean操作的方法,定义了Bean生命周期相关的抽象方法

4、AbstractAutowireCapableBeanFactory:抽象类,继承了AbstractBeanFactory,实现了Bean生命周期相关的内容,虽然是个抽象类,但它没有抽象方法

5、DefaultListableBeanFactory:继承与实现以上所有类和接口,是为Spring中最底层的BeanFactory, 自身实现了ListableBeanFactory接口

6、ApplicationContext:也是一个接口,我们会在下面有专门对它的介绍

SingletonBeanRegistry

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第17张

1、DefaultSingletonBeanRegistry: 定义了Bean的缓存池,类似于我们的BeanMap,实现了有关单例的操作,比如getSingleton(面试常问的三级缓存就在这里)

2、FactoryBeanRegistrySupport:提供了对FactoryBean的支持,比如从FactoryBean中获取Bean

BeanDefinition

BeanDefinition其实也是个接口(想不到吧),这里定义了许多和类信息相关的操作方法,方便在生产Bean的时候直接使用,比如getBeanClassName

它的大概结构如下(这里举例RootBeanDefinition子类):

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第18张

里面的各种属性想必大家也绝不陌生

同样的,它也有许多实现类:

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第19张

1、AnnotatedGenericBeanDefinition:解析配置类与解析Import注解带入的类时,就会使用它进行封装

2、ScannedGenericBeanDefinition:封装通过@ComponentScan扫描包所得到的类信息

3、ConfigurationClassBeanDefinition:封装通过@Bean注解所得到的类信息

4、RootBeanDefinition:ConfigurationClassBeanDefinition父类,一般在Spring内部使用,将其他的BeanDefition转化成该类

BeanDefinitionRegistry

定义了与BeanDefiniton相关的操作,如registerBeanDefinition,getBeanDefinition,在BeanFactory中,实现类就是DefaultListableBeanFactory

BeanDefinitionRegistryPostProcessor

插话:讲到这里,有没有发现Spring的命名极其规范,Spring团队曾言Spring中的类名都是反复推敲才确认的,真是名副其实呀,所以看Spring源码真的是一件很舒服的事情,看看类名方法名就能猜出它们的功能了。

该接口只定义了一个功能:处理BeanDefinitonRegistry,也就是解析配置类中的Import、Component、ComponentScan等注解进行相应的处理,处理完毕后将这些类注册成对应的BeanDefinition

在Spring内部中,只有一个实现:ConfigurationClassPostProcessor

BeanFactoryPostProcessor

所谓BeanFactory的后置处理器,它定义了在解析完配置类后可以调用的处理逻辑,类似于一个插槽,如果我们想在配置类解析完后做点什么,就可以实现该接口。

在Spring内部中,同样只有ConfigurationClassPostProcessor实现了它:用于专门处理加了Configuration注解的类

这里串场一个小问题,如知以下代码:

@Configuraiton public class MyConfiguration{ @Bean public Car car(){ return new Car(wheel()); } @Bean public Wheel wheel(){ return new Wheel(); } } 复制代码

问:Wheel对象在Spring启动时,被new了几次?为什么?

BeanPostProcessor

江湖翻译:Bean的后置处理器

该后置处理器贯穿了Bean的生命周期整个过程,在Bean的创建过程中,一共被调用了9次,至于哪9次我们下次再来探究,以下介绍它的实现类以及作用

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第20张

1、AutowiredAnnotationBeanPostProcessor:用于推断构造器进行实例化,以及处理Autowired和Value注解

2、CommonAnnotationBeanPostProcessor:处理Java规范中的注解,如Resource、PostConstruct

3、ApplicationListenerDetector: 在Bean的初始化后使用,将实现了ApplicationListener接口的bean添加到事件监听器列表中

4、ApplicationContextAwareProcessor:用于回调实现了Aware接口的Bean

5、ImportAwareBeanPostProcessor: 用于回调实现了ImportAware接口的Bean

ApplicationContext

ApplicationContext作为Spring的核心,以门面模式隔离了BeanFactory,以模板方法模式定义了Spring启动流程的骨架,又以策略模式调用了各式各样的Processor......实在是错综复杂又精妙绝伦!

它的实现类如下:

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第21张

1、ConfigurableApplicationContext:接口,定义了配置与生命周期相关操作,如refresh

2、AbstractApplicationContext: 抽象类,实现了refresh方法,refresh方法作为Spring核心中的核心,可以说整个Spring皆在refresh之中,所有子类都通过refresh方法启动,在调用该方法之后,将实例化所有单例

3、AnnotationConfigApplicationContext: 在启动时使用相关的注解读取器与扫描器,往Spring容器中注册需要用的处理器,而后在refresh方法在被主流程调用即可

4、AnnotationConfigWebApplicationContext:实现loadBeanDefinitions方法,以期在refresh流程中被调用,从而加载BeanDefintion

5、ClassPathXmlApplicationContext: 同上

从子类的情况可以看出,子类的不同之处在于如何加载BeanDefiniton, AnnotationConfigApplicationContext是通过配置类处理器(ConfigurationClassPostProcessor)加载的,而AnnotationConfigWebApplicationContext与ClassPathXmlApplicationContext则是通过自己实现loadBeanDefinitions方法,其他流程则完全一致

Spring的流程

以上,我们已经清楚了Spring中的主要角色以及作用,现在我们尝试把它们组合起来,构建一个Spring的启动流程

同样以我们常用的AnnotationConfigApplicationContext为例

spring到底是什么_Spring Web Flow_https://bianchenghao6.com/blog__第22张

图中只画出了Spring中的部分大概流程,详细内容我们会在后面的章节展开

小结

所谓万事开头难,本文初衷就是能让大家以由浅入深的方式认识Spring,初步建立Spring的认知体系,明白Spring的内部架构,对Spring的认知不再浮于表面。

现在头已经开了,相信后面内容的学习也将水到渠来。

本篇文章既讲是Spring的架构设计,也希望能成为我们以后复习Spring整体内容时使用的手册。

最后,看完文章之后,相信对以下面试常问的问题回答起来也是轻而易举

1、什么是BeanDefinition?

2、BeanFactory与ApplicationContext的关系?

3、后置处理器的分类与作用?

4、Spring的主要流程是怎么样的?

如果小伙伴觉得没办法很好回答上来的话就再看看文章,或者在评论区留下自己的见解吧

本篇文章主要讲了下 Spring SPI 机制、SpringBoot 自动装配原理,以及扩展点 ApplicationContextInitializer 在集成配置中心时的应用。篇幅有限,一些具体代码细节就没展开讲了,以后会出些文章针对某一个点进行详细讲解。

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复