写在前面的话,当前文章共有两部分,大览全局
Spring源码分析 {#Spring源码分析}
AnnotationConfigApplicationContext {#AnnotationConfigApplicationContext}
反推猜测应该完成什么?
- 生成bean对象 -> 创建beanFactory (bean工厂)
- BeanDefinition类 (加载bean信息, 通过注解得来的信息) -> 注解配置解析器AnnotationBeanDefinitionReader类
AnnotationBeanDefinitionReader中读取到不同的注解,有一系列的注解解析器去解析不同的注解
- 类路径扫描器 ClassPathBeanDefinitionScanner
- 系统属性扫描器 ...
深入AnnotationConfigApplicationContext注解
|---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public AnnotationConfigApplicationContext (Class<?>... componentClasses) { // 配置类可以有多个 // 调用无参数构造函数, 初始化三个重要对象 // 1. DefaultListableBeanFactory工厂: 生成bean对象的beanFactory工厂 // 2. AnnotatedBeanDefinitionReader: 对加了特定注解(如@Service、@Repository)的类进行读取转换为BeanDefinition对象 // 还要注册各种处理器: registerAnnotationConfigProcessors(), 通过此方法添加各种内置处理器, 其中最重要的: // 2.1 ★ConfigurationClassPostProcessor 是一个beanFactory后置处理器,用来完成bean的扫描与注入 // 2.2 AutowiredAnnotationBeanPostProcessor是一个bean的后置处理器, 依赖完成@Autowired自动注入 // 3. ClassPathBeanDefinitionScanner:对用户指定的包目录进行扫描查找bean对象的路径 扫描 this (); // 利用AnnotatedBeanDefinitionReader取将传进来的Configuration类做解析 // 将配置类Configuration注册到容器,但不实例化,其中最核心的方法为:doRegisterBean() this .register(componentClasses); // ***容器刷新*** @ComponentScan在这里完成解析 this .refresh(); }
|
this类中托管的各种注解解析器bean {#this类中托管的各种注解解析器bean}
this()方法
|------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public AnnotationConfigApplicationContext () { super (); //调用父类无参数构造方法,省略了 // startupStep类: 记录Application启动期间发生的特定阶段和操作的度量指标 StartupStep createAnnotatedBeanDefReader = this .getApplicationStartup().start( "spring.context.annotated-bean-reader.create" ); // 生成并注册BeanDefinition // 配置类 //1.org.springframework.context.annotation.internalConfigurationAnnotationProcessor // 自动配置 //2.org.springframework.context.annotation.internalAutowiredAnnotationProcessor // 特定注解 //3.org.springframework.context.annotation.internalCommonAnnotationPostProcessor // 事件监听 //4.org.springframework.context.event.internalEventListenerProcessor // 工厂 //5.org.springframework.context.event.internalEventListenerFactory this .reader = new AnnotatedBeanDefinitionReader ( this ); // 注解bean读取 createAnnotatedBeanDefReader.end(); // 注册默认的includeFilter this .scanner = new ClassPathBeanDefinitionScanner ( this ); }
|
至此发现还少了一个 DefaultListableBeanFactory
的工厂创建
构建工厂 {#构建工厂}
super()
点进父类 (GenericApplicationContext) -> super()
|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| public GenericApplicationContext () { this .customClassLoader = false ; this .refreshed = new AtomicBoolean (); // 父类构造器中创建了一个bean工厂,默认列表bean工厂 this .beanFactory = new DefaultListableBeanFactory (); }
|
到这发现我们猜想的三个功能 在this()中 全部找到
注册各种处理器 {#注册各种处理器}
this.reader = new AnnotatedBeanDefinitionReader(this)
注册处理器, 点进去
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| public AnnotatedBeanDefinitionReader (BeanDefinitionRegistry registry) { // 创建系统 属性及环境变量 getOrCreateEnvironment() // 查看this(xx,yy)构造方法 this (registry, getOrCreateEnvironment(registry)); }
|
构造方法 this(xx,yy)
,点进去
|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11
| public AnnotatedBeanDefinitionReader (BeanDefinitionRegistry registry, Environment environment) { this .beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE; this .scopeMetadataResolver = new AnnotationScopeMetadataResolver (); Assert.notNull(registry, "BeanDefinitionRegistry must not be null" ); Assert.notNull(environment, "Environment must not be null" ); this .registry = registry; // 内部类用于解析 @Conditional注解 this .conditionEvaluator = new ConditionEvaluator (registry, environment, (ResourceLoader) null ); // 注册多种内置注解配置解析器 AnnotationConfigUtils.registerAnnotationConfigProcessors( this .registry); }
|
深入 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
|------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public static void registerAnnotationConfigProcessors (BeanDefinitionRegistry registry) { registerAnnotationConfigProcessors(registry, (Object) null ); } public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors (BeanDefinitionRegistry registry, @Nullable Object source) { // 创建Bean工厂 beanFactory DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null ) { // 逐步追加一些默认组件 // 第一个追加的组件 AnnotationAwareOrderComparator if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { // 对@Order、@Priority、Ordered接口进行排序的比较类 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { // @Autowired @Qualifier @Lazy注解解析器 beanFactory.setAutowireCandidateResolver( new ContextAnnotationAutowireCandidateResolver ()); } } // BeanDefinitionHolder: 有名字和别名的 Set<BeanDefiniti onHolder> beanDefs = new LinkedHashSet ( 8 ); RootBeanDefinition def; // 判断容器是否有internalConfigurationAnnotationProcessor 这个bean if (!registry.containsBeanDefinition( "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" )) { // 创建一个配置类处理器,托管成Bean ConfigurationClassPostProcessor def = new RootBeanDefinition (ConfigurationClassPostProcessor.class); // 补充一个属性值 source def.setSource(source); // 在registerPostProcessor()中将 RootBeanDefinition 包装成 BeanDefinitionHolder, 为什么? // BeanDefinition添加了alias(别名) // 另外, 注册此bean到容器是在 在registerPostProcessor完成的 (仅仅是加载到容器中) beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" )); } if (!registry.containsBeanDefinition( "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" )) { // 没有则创建 AutowiredAnnotationBeanPostProcessor 并且托管 def = new RootBeanDefinition (AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" )); } // 省略其他的处理器,当前仅留俩个样例 return beanDefs; // 返回BeanHolderProcess集合 }
|
梳理一下:
super() : 初始化bean工厂
new AnnotatedBeanDefinitionReader(this) : 创建各种各样的处理器
register注册配置类 {#register注册配置类}
注册@Configuration类
this.register(componentClasses)
|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10
| public void register (Class<?>... componentClasses) { // 断言 Assert.notEmpty(componentClasses, "At least one component class must be specified" ); StartupStep registerComponentClass = this .getApplicationStartup().start( "spring.context.component-classes.register" ).tag( "classes" , () -> { return Arrays.toString(componentClasses); }); // 注册配置类 (点进去) this .reader.register(componentClasses); registerComponentClass.end(); }
|
this.reader.register(componentClasses);
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10
| public void register (Class<?>... componentClasses) { Class[] var2 = componentClasses; int var3 = componentClasses.length; // 循环遍历componentClass组件类 for ( int var4 = 0 ; var4 < var3; ++var4) { Class<?> componentClass = var2[var4]; // 注册bean this .registerBean(componentClass); } }
|
真正注册bean 的方法
|------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| private <T> void doRegisterBean (Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { // 解析包装传入的 Configuration类,变成AnnotatedGenericBeanDefinition对象 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition (beanClass); // 判断是否要跳过,判断依据是此类上是否有@Conditional注解 if (! this .conditionEvaluator.shouldSkip(abd.getMetadata())) { // 回调函数 abd.setInstanceSupplier(supplier); // Scope值 ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(abd); // 默认设置scope是singleton abd.setScope(scopeMetadata.getScopeName()); // 如果有定义bean的名字则用定义的,否则则获取并生成 String beanName = name != null ? name : this .beanNameGenerator.generateBeanName(abd, this .registry); // 处理类上面的通用注解: 如@Lazy @Primary @DependsOn,解析出左边的注解,保存到BeanDefinition中 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); int var10; int var11; if (qualifiers != null ) { Class[] var9 = qualifiers; var10 = qualifiers.length; for (var11 = 0 ; var11 < var10; ++var11) { Class<? extends Annotation > qualifier = var9[var11]; if (Primary.class == qualifier) { abd.setPrimary( true ); } else if (Lazy.class == qualifier) { abd.setLazyInit( true ); } else { abd.addQualifier( new AutowireCandidateQualifier (qualifier)); } } } // 用户自定义注解 if (customizers != null ) { // 类必须实现BeanDefinitionCustomizer接口 BeanDefinitionCustomizer[] var13 = customizers; var10 = customizers.length; for (var11 = 0 ; var11 < var10; ++var11) { BeanDefinitionCustomizer customizer = var13[var11]; customizer.customize(abd); } } // 到此还没有实例化,仅仅是构建了一个BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (abd, beanName); // 应用scopeProxyMode 代理模式 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); // 把BeanDefinitionHolder注册到registry容器中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this .registry); // registerBeanDefinition注册bean } }
|
梳理一下:
三步:
- this()注册了默认的Bean
- register()注册配置类的Bean (registerBeanDefinition()方法)
- 那么还剩一个refresh则是用于 注册自定义的Bean
refresh()所有的 bean 的创建以及初始化 {#refresh-所有的-bean-的创建以及初始化}
Spring的 refresh()
方法会触发所有bean的 ++创建++ 和 ++初始化++ 过程。当调用 refresh()
方法时,Spring容器会执行一系列的步骤,包括创建BeanFactory、加载Bean定义、实例化Bean、依赖注入、初始化Bean等。
在 refresh()
方法中,Spring会遍历所有注册的Bean定义,根据定义创建相应的Bean实例,并对这些实例进行初始化。这个过程包括调用Bean的构造函数创建实例,设置Bean的属性值,执行Bean的初始化方法等。这样,所有的Bean都会经过这个过程,完成它们的创建和初始化。
需要注意的是, refresh()
方法并 ++不会销毁已经存在++ 的Bean实例。它主要用于重启Spring容器,重新加载和初始化Bean。如果需要销毁已经存在的Bean实例,可以使用 destroy()
方法或者通过配置合适的作用域(如prototype)来控制Bean的生命周期。
非常重要的方法 invokeBeanFactoryPostProcessors bean工厂的后置处理器
Refresh()
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| public void refresh () throws BeansException, IllegalStateException { synchronized ( this .startupShutdownMonitor) { // 设置同步标识 StartupStep contextRefresh = this .applicationStartup.start( "spring.context.refresh" ); // Prepare this context for refreshing. // 1. 调用容器准备刷新的方法, 获取容器的时间,包括设置上下文状态,获取属性,验证必要的属性等 // ▶可以实现initPropertySources()方法, 添加属性或设置需要验证的属性 this .prepareRefresh(); // Tell the subclass to refresh the internal bean factory // 2. ★★★★★获取新的beanFactory,刷新BeanFactory和获取getBeanFactory --> 获取IOC容器 // 如果在这里断点,只会发现它仅仅完成了beanFactory设置序列化id ConfigurableListableBeanFactory beanFactory = this .obtainFreshBeanFactory(); // Prepare the bean factory for use in this context, 为BeanFactory配置容器亏秤,如类加载器,事件处理器 // 3. 填充BeanFactory功能, 配置容器特性 // 例如设置ClassLoader,设置SpEL表达式解析器,添加忽略注入的接口,添加三个和环境相关的bean (SpEL: 例如@Value("#{name}")) // 添加两个bean后置处理器BeanPostProcessor(ApplicationContextAwareProcessor和ApplicationListenerDetector)等 this .prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses // 4. 在这里是空方法(模版语法),子类可以重写这个方法,可以在BeanFactory创建并与准备完成后做进一步的设置 // 即子类处理自定义的BeanFactoryPostProcess this .postProcessBeanFactory(beanFactory); // 为容器的子类指定特殊的post事件处理器 StartupStep beanPostProcess = this .applicationStartup.start( "spring.context.beans.post-process" ); /* 以下两点是关于后置处理器的激活 Spring中会发现有很多后置处理器,但最终可以分为两种 (1)BeanFactoryPostProcessor,用于干预BeanFactory的创建过程 (2)BeanPostProcessor,用于干预Bean的创建过程 后置处理器的作用非常重要,Bean的创建以及AOP的实现全部依赖后置处理器 */ // Invoke factory processor registered as beans in the context // 5. ★★★★★ 激活各种BeanFactory处理器,调用所有注册的BeanFactoryPostProcessor的Bean // BeanFactoryPostProcessor可以在工厂初始化后,让用户做一些定制型的工作.(实现此BeanFactoryPostProcessor接口) // 执行所有的BeanFactoryPostProcessor,包括自定义的,以及Spring内置的 // 默认情况下,容器中只有一个BeanFactoryPostProcessor,即Spring内置的ConfigurationClassPostProcessor(★这个类很重要) // 会先执行实现了BeanDefinitionRegistryPostProcessor接口的类,然后执行BeanFactoryPostProcessor的类 // ★★★★ ConfigurationClassPostProcessor类的postProcessorBeanFactory()方法进行了@Configuration类的解析,@ComponentScan的扫描,@Import注解的处理 // 进过了这一步以后,会将所有交由Spring管理的bean对应的BeanDefinition放入beanFactory的beanDefinitionMap中 // 同时ConfigurationClassPostProcessor类的postProcessorBeanFactory()方法执行完后: // 向容器中添加了一个后置处理器-- ImportAwareBeanPostProcessor this .invokeBeanFactoryPostProcessors(beanFactory); //★★★★★★ 及其重要,在这里完成了 @ComponentScan的扫描,@Import注解的处理 // Register bean processor that intercept creation. // 6. ★★★注册BeanPostProcessor后置处理器 // AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean,并注入) // RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法) // CommonAnnotationBeanPostProcessor(处理@PreDestroy @PostConstruct @Resource等多个注解的作用)等 // AutoProxyCreator(处理AOP代理 @Aspect) this .registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // 7. 初始化信息源(做国际化功能: 消息绑定,消息解析) this .initMessageSource(); // 8. 初始化事件派发器,在注册监听器时会用到 this .initApplicationEventMulticaster(); // 9. 这也是一个挂载点,一个空方法,由子类实现(不同的Spring容器做不同的实现),在容器监听的时候可以自定义逻辑 this .onRefresh(); // 10. 注册监听器,派发之前步骤产生的一些事件(尽可能没有) this .registerListeners(); // 11. ***** 初始化剩下的单例Bean(非延时加载的) 真正的初始化bean的方法 this .finishBeanFactoryInitialization(beanFactory); // 12. 初始化容器的生命周期事件处理器,并发布容器的生命周期事件 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(); } } }
|
@ComponentScan属性的读取 {#ComponentScan属性的读取}
逐步读取 {#逐步读取}
目标: 读取basePackages设置的类
寻找的目录指引如下:(以下每一步操作均为追踪描述方法后的指引介绍)
- 入口 AnnotationConfigApplicationContext
- 当前类下的构造器实现重载解析类的方法 找到
refresh()
, ★invokeBeanFactoryPostProcessors
方法(重要),- 然后可以找到一个后置处理器的委托代理类 (PostProcessorRegistrationDelegate) ,其中有方法为 invokeBeanFactoryPostProcessors
- 在当前方法中找到 if-else中的 invokeBeanFactoryPostProcessors 方法(中间处理bean工厂类上加了注解的,比如@Primary,@Order排序), 不论走if还是else 都会激活bean工厂的后置处理器
invokeBeanFactoryPostProcessors
- 找到
postProcessor.postProcessBeanFactory(beanFactory)
这一行, 当前行为后置处理器处理bean工厂, 点进postProcessBeanFactory方法发现什么都没有, 他是一个@FunctionalInterface接口(函数接口), 找实现类(如下图),
- 找到 postProcessBeanFactory 方法(bean工厂的后置处理器)
|---------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if ( this .factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException ( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } else { this .factoriesPostProcessed.add(factoryId); // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then // 判断已注册的PostProcessor是否包含了factoryId if (! this .registriesPostProcessed.contains(factoryId)) { // ★正式处理配置Bean定义 @Configuration -> 里面带了一个@ComponentScan this .processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory); } // 代理 this .enhanceConfigurationClasses(beanFactory); // Import感知 @Import({A.class}) beanFactory.addBeanPostProcessor( new ImportAwareBeanPostProcessor (beanFactory)); } }
|
- 追踪processConfigBeanDefinitions
|------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public void processConfigBeanDefinitions (BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList (); String[] candidateNames = registry.getBeanDefinitionNames(); String[] var4 = candidateNames; int var5 = candidateNames.length; // 迭代所有候选的bean名字 for ( int var6 = 0 ; var6 < var5; ++var6) { String beanName = var4[var6]; BeanDefinition beanDef = registry.getBeanDefinition(beanName); // 判断上面是否包含ConfigurationClass属性 if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null ) { // 略 (如果有则加入候选) } if (!configCandidates.isEmpty()) { // 配置类候选排序(@Order,@Priority排序标志) configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); SingletonBeanRegistry sbr = null ; // 检查是否为单例bean if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry)registry; if (! this .localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton( "org.springframework.context.annotation.internalConfigurationBeanNameGenerator" ); if (generator != null ) { this .componentScanBeanNameGenerator = generator; this .importBeanNameGenerator = generator; } } } // 环境,如果没有则标准环境 if ( this .environment == null ) { this .environment = new StandardEnvironment (); } // Parse each @Configuration class // ★★★★解析每一个@Configuration类,包括@ComponentScan ConfigurationClassParser parser = new ConfigurationClassParser ( this .metadataReaderFactory, this .problemReporter, this .environment, this .resourceLoader, this .componentScanBeanNameGenerator, registry); // 上述配置类解析器包括:注解元信息的读取工厂、问题报告器、标准系统环境变量、资源加载器、组件扫描bean名字构建器 Set<BeanDefinitionHolder> candidates = new LinkedHashSet (configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet (configCandidates.size()); do { // 一个一个的读取候选的配置(可以有多个配置类,一次读取一个) StartupStep processConfig = this .applicationStartup.start( "spring.context.config-classes.parse" ); // ★★★★★★ 真正的解析器在此 parser.parse(candidates); // candidate 候选集合(多个配置类) parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet (parser.getConfigurationClasses()); // 下面代码略 } }
|
- 追踪parse (8中源码注释标★★★★★★)
|------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void parse (Set<BeanDefinitionHolder> configCandidates) { Iterator var2 = configCandidates.iterator(); // 循环迭代每一个Configuration类,parse()解析 while (var2.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next(); BeanDefinition bd = holder.getBeanDefinition(); // 开始判断注解属于什么类 try { if (bd instanceof AnnotatedBeanDefinition) { this .parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) { this .parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName()); } else { this .parse(bd.getBeanClassName(), holder.getBeanName()); } } // catch异常处理处(略) } this .deferredImportSelectorHandler.process(); }
|
在此处总结发现, 源码中凡是嵌套if-eles的, 最后都会调用 同一个方法, 方法的重载
- 继续追踪重载的parse
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7
| protected final void parse ( @Nullable String className, String beanName) throws IOException { Assert.notNull(className, "No bean class name for configuration class bean definition" ); // 元数据读取 MetadataReader reader = this .metadataReaderFactory.getMetadataReader(className); // ★ 处理配置类 this .processConfigurationClass( new ConfigurationClass (reader, beanName), DEFAULT_EXCLUSION_FILTER); }
|
- 追踪processConfigurationClass,★★★★★然后追踪do-while里面的递归处理配置类
在此处先是处理条件注解@Conditional, 然后判断配置类, 没导入则合并 marginImport
do-while中递归读取配置类方法 doProcessConfigurationClass
.
在@Configuration注解中它包括了@Component注解 .
|---------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Nullable protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { // 第一步判断配置类上是否有@Component注解 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { this .processMemberClasses(configClass, sourceClass, filter); } // 属性资源读取 (eg: @PropertySource("classpath:db.properties")) Iterator var4 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator(); AnnotationAttributes importResource; while (var4.hasNext()) { importResource = (AnnotationAttributes)var4.next(); // 有则处理 if ( this .environment instanceof ConfigurableEnvironment) { this .processPropertySource(importResource); } else { this .logger.info( "Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment" ); } } // ★★★★★目标到达★★★★★ Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); // 如果包扫描注解不是空 并且 不跳过 if (!componentScans.isEmpty() && ! this .conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { // 迭代器遍历包扫描的注解 Iterator var14 = componentScans.iterator(); while (var14.hasNext()) { AnnotationAttributes componentScan = (AnnotationAttributes)var14.next(); // The config class is annotated with @ComponentScan -> perform the scan immediatel // ★★★★★ 这个parse真正处理@ComponentScan中的basePackages Set<BeanDefinitionHolder> scannedBeanDefinitions = this .componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); Iterator var8 = scannedBeanDefinitions.iterator(); // Check the set of scanned definitions for any further config classes and parse recursively if needed while (var8.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next(); BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null ) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this .metadataReaderFactory)) { this .parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // @Import this .processImports(configClass, sourceClass, this .getImports(sourceClass), filter, true ); importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); // 略 return null ; }
|
对于上述源码的parse:
-
首先建立了一个ClassPathBeanDefinitionScanner扫描器, 扫描@ComponentScan, 以及是否要过滤(includeFilters)
-
包扫描器获取名字, 获取作用域(设置), 资源模式, 扫描过滤条件(包含过滤器,扫描过滤器), 判断是否为懒加载(lazyInit)
-
★★★★★ 期盼的 (扫描basePackages)
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
1 2 3 4 5
|// 情况一 basePackages Set<String> basePackages = new LinkedHashSet (); String[] basePackagesArray = componentScan.getStringArray( "basePackages" ); // 情况二 basePackageClasses Class[] var20 = componentScan.getClassArray( "basePackageClasses" );
| -
判断是否为空, 假如为空, 则获取 当前注解类的包路径
-
最后看看是否有筛选, 过滤
到此,包名准备完毕, 然后 递归扫描
|-----------|-------------------------------------------------------------------------|
| 1
| return scanner.doScan(StringUtils.toStringArray(basePackages));
|
doScan递归扫描 {#doScan递归扫描}
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| /* 1. 资源扫描 扫描包路径下.class文件, 将资源转换为Resource 2. 资源加载 通过ASM框架获取class元数据,封装BeanDefinition 3. 资源解析 获取bean上注解的属性值, 如@Scope 4. 生成Bean 生成beanName, 设置Bean默认值(懒加载,初始化方法等) 代理模式 5. 注册Bean 把BeanDefinition放入IOC容器DefaultListableBeanFactory */ protected Set<BeanDefinitionHolder> doScan (String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified" ); //创建一个集合,存放扫描到的Bean定义封装类 // 无序,不可重复, BeanDefinitionHolder包了一个BeanDefinition: bean的定义类:关于一个bean所有的相关信息 // (scope,lazy,initmethod,destroymethod...) Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet <>(); //遍历扫描所有给定的包路径 for (String basePackage : basePackages) { //** 调用父类ClassPathScanningCandidateComponentProvider的方法 // 扫描指定类路径, 获取符合条件的Bean定义, 并存入集合beanDefinitions中 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //遍历BeanDefinition (扫描到的bean) for (BeanDefinition candidate : candidates) { //** 获取@Scope的值,即获取scope的作用域, scope取值: singleton,prototype ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(candidate); // 为bean 设置作用域 candidate.setScope(scopeMetadata.getScopeName()); //** 为bean生成名字 String beanName = this .beanNameGenerator.generateBeanName(candidate, this .registry); // 设置Bean的自动依赖注入装配属性等 ****这里每一个bean 先设置默认值(lazy,autowiredMode,dependency,init,destroy) if (candidate instanceof AbstractBeanDefinition) { //* -> applyDefaults 给默认值设置一个bean的属性 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } // 如果扫描到的bean是Spring的注解bean,则处理其通用的Spring注解 // 再设置这个bean上的用户配置值 if (candidate instanceof AnnotatedBeanDefinition) { //** 解析通用注解(@Lazy、@Primary、@DependsOn、@Role、@Description注解),为这些注解设置值 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 冲突检查 if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); beanDefinitions.add(definitionHolder); //** 在容器中注册扫描到的bean registerBeanDefinition(definitionHolder, this .registry); } } } return beanDefinitions; }
|
简化注册扫描 {#简化注册扫描}
以往
|-------------|---------------------------------------------------------------------------------------------------|
| 1 2
| ApplicationContext context = new AnnotationConfigApplicationContext (SpringConfig.class);
|
通过读取配置类, 然后读取配置类上面的@ComponentScan注解, 然后在扫描
现在
|-------------|-------------------------------------------------------------------------------------------------------------|
| 1 2
| ApplicationContext context = new AnnotationConfigApplicationContext (basePackages = "com.spring" );
|
通过使用AnnotationConfigApplicationContext的重载方法, 直接扫描指定的basePackages路径, 省略了读取配置类在读取注解的流程
使用这个方案, 也就是直接走到了 scanner.doScan(StringUtils.toStringArray(basePackages));
方法而不需要绕来绕去的解析
缺点: 路径固定
上部分小总结 {#上部分小总结}
refresh
实例化(循环依赖) {#实例化-循环依赖}
流程了解 {#流程了解}
既然都得到了扫描到的对象 Set<BeanDefinition>
接下来需要做的就是实例化对象了
其中实例化包括
- @Value 设置属性
- @Autowired 注入依赖
然后 存入map
通过getBean()获取IOC容器中的bean
从容器中取的流程:
- 懒加载模式: content.getBean() -> getBean -> doGetBean()
- 非懒加载模式: finishBeanFactoryInitialization() -> beanFactory.preInstantiateSingletons() 生成 ++一个单例bean++ -> getBean() -> doGetBean()
所以两类都是殊途同归 doGetBean()
如何解决循环依赖 {#如何解决循环依赖}
循环依赖, 依赖成为一个环, 互相依赖
构造方法循环依赖 {#构造方法循环依赖}
-
在构造器循环依赖的每一个构造器上面加注解 ++@Lazy++
-
代码重构
-
改为字段依赖注入
使用注意点是:
@Lazy注解:
- 初始化注入 代理对象 时, 真实调用时使用Spring AOP动态代理去 关联 真实对象, 然后通过反射完成调用
- 加在构造器上, 作用域为构造器所有参数, 加在某个参数上, 作用域为该参数
- 作用在接口上, 使用JDK动态代理, 这样在类上, 使用CGLib动态代理
Setter循环依赖 {#Setter循环依赖}
字段注入循环依赖,Spring官方通过三层缓存解决, 解决方案:
setter注入下 实例化 (无参构造方法) 和依赖属性注入**(set或属性)**是分开的, 这是其可以解决循环依赖最根本的原因
getBean中创建Bean的流程 {#getBean中创建Bean的流程}
doGetBean() {#doGetBean}
|------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| protected <T> T doGetBean ( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { // 根据指定的名称获取被管理的Bean的名字, 剥离指定名称中对容器的相关依赖 // 如果指定的是别名,那么将别名转换为规范的Bean名称 // <1>获取beanName: 传入参数name可能是别名,也有可能是FactoryBean, 所以需要一系列的解析 // 为FactoryBean时,name为 "&工厂名" ,还要别名的情况 String beanName = transformedBeanName(name); Object beanInstance; // Eagerly check singleton cache for manually registered singletons. // 从缓存中获取已被创建过的单例Bean // ***<2>从缓存中获取单例bean,避免循环依赖 Object sharedInstance = getSingleton(beanName); // 单例模型 (getSingleton方法看下面源码部分) // 如果缓存中有此单例Bean if (sharedInstance != null && args == null ) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace( "Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference" ); } else { logger.trace( "Returning cached instance of singleton bean '" + beanName + "'" ); } } beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } else { // 省略 } finally { beanCreation.end(); } } return adaptBeanInstance(name, beanInstance, requiredType); }
|
getSingleton() {#getSingleton}
只有单例才会有这个,原型模式不会调用此方法
|------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| // Spring对单例的bean只会创建一次,后续获取则都是在缓存中获取 // 该过程体现在 #getSingleton(String beanName)中 /* 三级缓存机制的理解: 目标避免循环依赖 一级: 从singletonObjects获取实例 否则:从earlySingletonObjects获取 否则: 从singletonFactories获取beanName对应的ObjectFactory,在调用getObject()来创建bean,并放到earlySingletonObjects中 并从singletonFactories中删除此ObjectFactory */ @Nullable protected Object getSingleton (String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock // 从单例缓存(一级缓存)中获取单例bean: 用来存已经完成初始化的单例bean Object singletonObject = this .singletonObjects.get(beanName); // 如果缓存中没有 并且 该bean真正创建(在singletonsCurrentlyInCreation集中存在此bean的名字) // ★★★ isSingletonCurrentlyInCreation(beanName) if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 从二级缓存earlySingletonObjects中取 已经创建但是没有属性注入 singletonObject = this .earlySingletonObjects.get(beanName); // earlySingletonObjects中没有,且运行提前创建 if (singletonObject == null && allowEarlyReference) { // 双重检查锁 // 防止重复创建,使用正式创建bean前锁定(单例模型的双重检查锁:当前判断了两次singletonObject,在锁之前和锁之后) synchronized ( this .singletonObjects) { // Consistent creation of early reference within full singleton lock singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { // earlySingletonObjects中没有,且运行提前创建 singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null ) { // 从三级缓存 singletonFactories 中获取对应的ObjectFactory ObjectFactory<?> singletonFactory = this .singletonFactories.get(beanName); if (singletonFactory != null ) { // 从单例工厂中获取bean singletonObject = singletonFactory.getObject(); // 存入(early, 注意此时还没有添加属性(populateBean用来注入属性的),添加到二级缓存) this .earlySingletonObjects.put(beanName, singletonObject); // 从三级缓存中删除 this .singletonFactories.remove(beanName); } } } } } } return singletonObject; }
|
三级缓存的理解:目标 避免循环依赖
++一级++ : 从 ++singletonObjects++ 获取实例
++二级++ ------>否则:从 ++earlySingletonObjects++ 获取
++三级++ ------------>否则: 从 ++singletonFactories++ 获取beanName对应的ObjectFactory,在调用getObject()来创建bean,并放到earlySingletonObjects中
------------------>并从singletonFactories中删除此ObjectFactory
一级缓存(singletonObjects): 是一个 完整 的Bean -
二级缓存(earlySingletonObjects): bean的实例,但是 没有属性 ( 属性还没有注入,所以说构造方式没办法解决循环依赖,set注入可以 ) , 早期的bean
三级缓存(singletonFactories ): 存放bean的原始工厂,其内容与二级缓存中的无异
Spring解决循环依赖(在此仅考虑 set/属性注入,单例 情况)是依靠 Bean的中间态 (一级:完整bean 二级:没有属性的bean 三级;ObjectFactory)这个概念, 而中间态是指bean的初始化状态
实例化的过程又是通过构造器创建的,如果A还没创建出来就不能提前曝光(对象工厂,三级缓存ObjectFactory), 所以构造器的循环依赖无法解决
双重检查锁 : 单例, 在一级缓存和二级缓存后加锁,加锁后再走一遍判断一级二级缓存中是存在singletonObject对象
SpringBoot的启动流程 {#SpringBoot的启动流程}
简要概述 {#简要概述}
我们的springboot项目是通过 SpringApplication.run(class)
方法启动的。传进去的那个类一般是我们的启动类。run方法的底层会先包装一个 SpringApplication
对象。在构造函数里面会通过依赖的包确定我们运行的 web环境
(servlet还是reactive),保存我们传进去的 启动类
,从 spring.factories
文件中加载 初始化器
和 监听器
。
对象创建好后,调用他的run方法,也就是springboot启动的核心。里面会创建StopWatch对项目启动进行计时。会根据web类型,创建不同的 上下文context
。会打印项目启动的 banner
。有两个比较核心的操作,是 容器初始化
和 容器刷新
的操作。
容器初始化
会调用对象保存的所有初始化器,这些初始化器可能会对cntext进行一些配置,或者注册一些bean进去。同时也会把之前传进去的 启动类
注册成bean,这样后续能够根据启动类的注解 @SpringBootApplication
扫描项目路径下的包和自动装配的类。
容器刷新
就是调用spring上下文原生的refresh方法,进行容器的刷新逻辑。
在这期间,不同的阶段,springboot都会通知给监听器,如果我们关心这些阶段想做对应动作,可以实现 SpringApplicationRunListener
或者 ApplicationListener
类,,并且要在 spring.factories
文件中配置。
最后容器启动成功,会通知给监听器,如果我们想获得更多信息,比如run的args,也可以实现 ApplicationRunner
或 CommandLineRunner
方法。一般做一些 预热 或者初始化操作可以用这个方法。
源码级追踪 {#源码级追踪}
对于一个SpringBoot项目,在前置准备全部完成后,我们的入口会是这样的
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| @SpringBootApplication public class CalyeeApplication { public static void main (String[] args) { SpringApplication.run(CalyeeApplication.class, args); } }
|
@SpringBootApplication
{#SpringBootApplication}
对于SpringBootApplication注解,其实他是一个复合注解
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11
| @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} )
|
@SpringBootConfiguration
{#SpringBootConfiguration}
对于这个注解,其实他就是一个Spring的@Configuration注解,他标明这个类需要作为一个配置类给Spring IOC托管
|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration // <- @Indexed public @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods () default true ; }
|
@ComponentScan
{#ComponentScan}
这个其实也没什么,其实就是组件的扫描,然后里面还可以编写一些过滤逻辑/排除逻辑(excludeFilters、@Filter)
@EnableAutoConfiguration
{#EnableAutoConfiguration}
这个注解才是实现 自动装配的关键 ,点进去之后发现,它是一个由@AutoConfigurationPackage和@lmport
注解组成的复合注解。
|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11
| @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 {}; }
|
@lmport导入了一个类 AutoConfigurationImportSelector.class
,在有之前阅读过源码的经验,这个其实就是 自动装配导入选择器 ,在此仅列出类继承部分
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1
| public class AutoConfigurationImportSelector implements DeferredImportSelector , BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
|
具体自动装配的路径跟踪,笔者可以沿着 AutoConfigurationImportSelector(类):org.springframework.boot.autoconfigure.AutoConfigurationlmportSelector#getCandidateConfiguration
SpringFactoriesLoader.loadFactoryNames这个方法就是加载 spring.factories
的所有某个类型的数
据。根据第一个参数,就是查出所有自动装配的类(其实这个可以看作 SPI 在SpringBoot中的运用)
这样就会在beanDefinetion阶段把这些自动装配的类注册进去了。
对象创建 {#对象创建}
沿着run方法追踪进去,他构建了一个SpringApplication对象,然后再调用run方法启动SpringBoot项目,其中我们可以发现有
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3
| public static ConfigurableApplicationContext run (Class<?>[] primarySources, String[] args) { return new SpringApplication (primarySources).run(args); }
|
#SpringApplication
|---------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public SpringApplication (ResourceLoader resourceLoader, Class<?>... primarySources) { this .resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null" ); //设置源 //通常Springboot的启动类就是源 this .primarySources = new LinkedHashSet <>(Arrays.asList(primarySources)); //推断并设置WEB应用程序类型 //根据classpath下的类来推断 this .webApplicationType = WebApplicationType.deduceFromClasspath(); //加载并设置Bootstrapper this .bootstrapRegistryInitializers = new ArrayList <>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); //加载并设置初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //加载并设置应用事件监听器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //推断并设置应用程序主类的class对象 this .mainApplicationClass = deduceMainApplicationClass(); }
|
其中SpringApplication中的构造函数就是做了如下的事件:
- 设置源,其中在SpringBoot中的源一般都是SpringBoot的启动类
- 设置Web应用程序类型。通过判断classpath下是否存在某些类,来推断当前WEB应用程序的类型
- 加载并设置Bootstrapper,ApplicationContextlnitializer和ApplicationListener。借助
SpringFactoriesLoader基于SPI机制完成Bootstrapper,ApplicationContextlnitializer和
ApplicationListener的加载,然后设置到SpringApplication中; - 设置应用程序主类的Class对象。
设置源 {#设置源}
在SpringBoot中,一般源都为SpringBoot的启动类本身
设置Web应用程序类型 {#设置Web应用程序类型}
WebApplicationType#deduceFromClasspath
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12
| static WebApplicationType deduceFromClasspath () { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null ) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null ) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null )) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null )) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
|
其实就是判断是不是Servlet(目前MVC常用的)
加载并设置Bootstrapper {#加载并设置Bootstrapper}
SpringApplication#getSpringFactoriesInstances
|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9
| private <T> Collection<T> getSpringFactoriesInstances (Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates // 通过SpringFactoriesLoader加载工厂名的类 Set<String> names = new LinkedHashSet <>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
|
其实就是跟之前的自动装配很像,他也是拿全限定名 例如
|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer # 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.DelegatingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
|
那么在此可以发现,与自动装配不同的是,这次拿的不是那些自动配置类 如: MyBatisPlusAutoConfiguration
查到这些类的全限定名后,就调用它们的无参构造器进行实例化,并保存起来,方便后续在run代码里调用。
设置应用程序主类的Class对象 {#设置应用程序主类的Class对象}
|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException ().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ( "main" .equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null ; }
|
通过当前堆栈找到主类
执行Run方法启动项目 {#执行Run方法启动项目}
SpringApplication#run(String... args)
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| /** * Run the Spring application, creating and refreshing a new * { @link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running { @link ApplicationContext} */ public ConfigurableApplicationContext run (String... args) { long startTime = System.nanoTime(); // 记录启动时间(其实就是用于记录启动的时间) DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null ; configureHeadlessProperty(); //[1] 从spring.factories加载配置的SpringApplicationRunListener,springboot黑认引入EventPublishingRunListener //EventPublishingRunListener对象主要用来发射SpringBoot启动过程中内置的一些生命周期事件,通知给ApplicationListener //其实就是在上面分析的 #加载并设置Bootstrapper SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this .mainApplicationClass); // 根据预先配置上下文对象,通知容器启动 try { ApplicationArguments applicationArguments = new DefaultApplicationArguments (args); // [2] 准备启动的环境,例如application.properties(系统环境变量,命令行参数等) ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); // [3] 控制台打印SpringBoot的banner标识 Banner printedBanner = printBanner(environment); // [4] 根据不同的环境创建不同的上下文容器 context = createApplicationContext(); context.setApplicationStartup( this .applicationStartup); // [*] 初始化容器(在此没有标序号,因为它很重要) prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // [5] 刷新容器,调用容器的refresh方法,详情见spring源码 refreshContext(context); // [6] 执行刷新容器后的后置方法,其中当前为空方法 afterRefresh(context, applicationArguments); // [7] 停止启动计时 Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if ( this .logStartupInfo) { /// 打印日志 new StartupInfoLogger ( this .mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } //->发送[ApplicationStartedEvent]事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕 listeners.started(context, timeTakenToStartup); // [8] 调用ApplicationRunner和CommandLineRunner的run方法,实现spring容器启动后需要做的一些东西比如加载一些业务数据等 callRunners(context, applicationArguments); } catch (Throwable ex) { // 启动过程中发送异常事件,使用handleRunFailure来报告异常 handleRunFailure(context, ex, listeners); throw new IllegalStateException (ex); } try { // ApplicationReadEvent事件标志着SpringApplication已经正在运行即已经成功启动,可以接收服务请求了 Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { //若出现异常,此时仅仅报告异常,而不会发送任何事件 handleRunFailure(context, ex, null ); throw new IllegalStateException (ex); } // [9] 最终返回容器 return context; }
|
分析部分 {#分析部分}
加载监听器 {#加载监听器}
#[1] #getRunListeners
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| private SpringApplicationRunListeners getRunListeners (String[] args) { Class<?>[] types = new Class <?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners (logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this , args), this .applicationStartup); }
|
这个其实就是从 #getSpringFactoriesInstances
中获取 spring.factories
的全限名并加载 SpringApplicationRunListener
。这个就是SpringBoot的一系列的· 生命周期监听器
Tips:如果我们也需要扩展,那么是不是也可以直接实现ApplicationRunListener就可以拿到一些事件的的信息
banner {#banner}
#[3] 控制台打印SpringBoot的banner标识
这个其实就是在启动的时候可以修改对应的启动图标
创建对应的context容器 {#创建对应的context容器}
#[4] 根据不同的环境创建不同的上下文容器
(当前SpringBoot版本已经切换到2.6.7了,与之前的可能会有所差别,例如在2.1.0中,#createApplicationContext的逻辑为通过switch枚举容器类型创建对应的容器)
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3
| protected ConfigurableApplicationContext createApplicationContext () { return this .applicationContextFactory.create( this .webApplicationType); }
|
FunctionInterface #ApplicationContextFactory
|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ApplicationContextFactory DEFAULT = (webApplicationType) -> { try { for (ApplicationContextFactory candidate : SpringFactoriesLoader .loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) { ConfigurableApplicationContext context = candidate.create(webApplicationType); if (context != null ) { return context; } } return new AnnotationConfigApplicationContext (); } catch (Exception ex) { throw new IllegalStateException ( "Unable create a default ApplicationContext instance, " + "you may need a custom ApplicationContextFactory" , ex); } };
|
现在通过函数式工厂方法定义接口模板实现
初始化容器 {#初始化容器}
#[*] 初始化容器(#prepareContext)
|------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private void prepareContext (DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 将准备好的环境设置给上下文 context.setEnvironment(environment); postProcessApplicationContext(context); // 遍历所有的ApplicationContextInitializer的initialize()方法来对已经创建好的ApplicationContext进一步处理 applyInitializers(context); // 调用SpringApplicationRunListeners的contextPrepared()方法来通知所有的监听者说:"我的容器已经准备好了" listeners.contextPrepared(context); bootstrapContext.close(context); if ( this .logStartupInfo) { logStartupInfo(context.getParent() == null ); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 将springApplicationArguments注入到IOC容器 beanFactory.registerSingleton( "springApplicationArguments" , applicationArguments); if (printedBanner != null ) { // 注册springBootBanner beanFactory.registerSingleton( "springBootBanner" , printedBanner); } if (beanFactory instanceof AbstractAutowireCapableBeanFactory) { ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences( this .allowCircularReferences); if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding( this .allowBeanDefinitionOverriding); } } if ( this .lazyInitialization) { context.addBeanFactoryPostProcessor( new LazyInitializationBeanFactoryPostProcessor ()); } // Load the sources <-> 加载资源 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray( new Object [ 0 ])); // 调用SpringApplicationRunListener的contextLoaded()方法,通知所有的监听者:ApplicationContext已经装载完毕 listeners.contextLoaded(context); }
|
其中自动装配是在refresh的阶段实现的