写在前面的话,当前文章共有两部分,大览全局
Spring源码分析
SpringBoot的启动流程
Spring源码分析 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) { this (); this .register(componentClasses); this .refresh(); }
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 createAnnotatedBeanDefReader = this .getApplicationStartup().start("spring.context.annotated-bean-reader.create" ); this .reader = new AnnotatedBeanDefinitionReader (this ); createAnnotatedBeanDefReader.end(); this .scanner = new ClassPathBeanDefinitionScanner (this ); }
至此发现还少了一个DefaultListableBeanFactory
的工厂创建
构建工厂 super()
点进父类 (GenericApplicationContext) -> super()
1 2 3 4 5 6 public GenericApplicationContext () { this .customClassLoader = false ; this .refreshed = new AtomicBoolean (); this .beanFactory = new DefaultListableBeanFactory (); }
到这发现我们猜想的三个功能在this()中 全部找到
注册各种处理器 this.reader = new AnnotatedBeanDefinitionReader(this)
注册处理器, 点进去
1 2 3 4 5 public AnnotatedBeanDefinitionReader (BeanDefinitionRegistry registry) { 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; 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) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null ) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver ()); } } Set<BeanDefiniti onHolder> beanDefs = new LinkedHashSet (8 ); RootBeanDefinition def; if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor" )) { def = new RootBeanDefinition (ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" )); } if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor" )) { def = new RootBeanDefinition (AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" )); } return beanDefs; }
梳理一下:
super() : 初始化bean工厂
new AnnotatedBeanDefinitionReader(this) : 创建各种各样的处理器
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; for (int var4 = 0 ; var4 < var3; ++var4) { Class<?> componentClass = var2[var4]; 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) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition (beanClass); if (!this .conditionEvaluator.shouldSkip(abd.getMetadata())) { abd.setInstanceSupplier(supplier); ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = name != null ? name : this .beanNameGenerator.generateBeanName(abd, this .registry); 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[] var13 = customizers; var10 = customizers.length; for (var11 = 0 ; var11 < var10; ++var11) { BeanDefinitionCustomizer customizer = var13[var11]; customizer.customize(abd); } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this .registry); } }
梳理一下:
三步:
this()注册了默认的Bean
register()注册配置类的Bean (registerBeanDefinition()方法)
那么还剩一个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" ); this .prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this .obtainFreshBeanFactory(); this .prepareBeanFactory(beanFactory); try { this .postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this .applicationStartup.start("spring.context.beans.post-process" ); this .invokeBeanFactoryPostProcessors(beanFactory); this .registerBeanPostProcessors(beanFactory); beanPostProcess.end(); this .initMessageSource(); this .initApplicationEventMulticaster(); this .onRefresh(); this .registerListeners(); this .finishBeanFactoryInitialization(beanFactory); this .finishRefresh(); } catch (BeansException var10) { if (this .logger.isWarnEnabled()) { this .logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10); } this .destroyBeans(); this .cancelRefresh(var10); throw var10; } finally { this .resetCommonCaches(); contextRefresh.end(); } } }
@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); if (!this .registriesPostProcessed.contains(factoryId)) { this .processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory); } this .enhanceConfigurationClasses(beanFactory); 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; for (int var6 = 0 ; var6 < var5; ++var6) { String beanName = var4[var6]; BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null ) { } if (!configCandidates.isEmpty()) { configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); SingletonBeanRegistry sbr = null ; 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 (); } ConfigurationClassParser parser = new ConfigurationClassParser (this .metadataReaderFactory, this .problemReporter, this .environment, this .resourceLoader, this .componentScanBeanNameGenerator, registry); 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); 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(); 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()); } } } 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 { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { this .processMemberClasses(configClass, sourceClass, filter); } 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(); Set<BeanDefinitionHolder> scannedBeanDefinitions = this .componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); Iterator var8 = scannedBeanDefinitions.iterator(); 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()); } } } } 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 Set<String> basePackages = new LinkedHashSet (); String[] basePackagesArray = componentScan.getStringArray("basePackages" ); Class[] var20 = componentScan.getClassArray("basePackageClasses" );
判断是否为空, 假如为空, 则获取当前注解类的包路径
最后看看是否有筛选, 过滤
到此,包名准备完毕, 然后 递归扫描
1 return scanner.doScan(StringUtils.toStringArray(basePackages));
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 protected Set<BeanDefinitionHolder> doScan (String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified" ); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet <>(); for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this .beanNameGenerator.generateBeanName(candidate, this .registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); beanDefinitions.add(definitionHolder); 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循环依赖 字段注入循环依赖,Spring官方通过三层缓存解决, 解决方案:
setter注入下 实例化 (无参构造方法) 和依赖属性注入**(set或属性)**是分开的, 这是其可以解决循环依赖最根本的原因
getBean中创建Bean的流程 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 { String beanName = transformedBeanName(name); Object beanInstance; Object sharedInstance = getSingleton(beanName); 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() 只有单例才会有这个,原型模式不会调用此方法
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 @Nullable protected Object getSingleton (String beanName, boolean allowEarlyReference) { Object singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this .singletonObjects) { singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null ) { ObjectFactory<?> singletonFactory = this .singletonFactories.get(beanName); if (singletonFactory != null ) { singletonObject = singletonFactory.getObject(); 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项目是通过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注解,其实他是一个复合注解
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
对于这个注解,其实他就是一个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
这个其实也没什么,其实就是组件的扫描,然后里面还可以编写一些过滤逻辑/排除逻辑(excludeFilters、@Filter)
@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" ); this .primarySources = new LinkedHashSet <>(Arrays.asList(primarySources)); this .webApplicationType = WebApplicationType.deduceFromClasspath(); this .bootstrapRegistryInitializers = new ArrayList <>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this .mainApplicationClass = deduceMainApplicationClass(); }
其中SpringApplication中的构造函数就是做了如下的事件:
设置源,其中在SpringBoot中的源一般都是SpringBoot的启动类
设置Web应用程序类型。通过判断classpath下是否存在某些类,来推断当前WEB应用程序的类型
加载并设置Bootstrapper,ApplicationContextlnitializer和ApplicationListener。借助 SpringFactoriesLoader基于SPI机制完成Bootstrapper,ApplicationContextlnitializer和 ApplicationListener的加载,然后设置到SpringApplication中;
设置应用程序主类的Class对象。
设置源 在SpringBoot中,一般源都为SpringBoot的启动类本身
设置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 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(); 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对象 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) { } return null ; }
通过当前堆栈找到主类
执行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 public ConfigurableApplicationContext run (String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null ; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this .mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments (args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this .applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this .logStartupInfo) { new StartupInfoLogger (this .mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException (ex); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { handleRunFailure(context, ex, null ); throw new IllegalStateException (ex); } 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 #[3] 控制台打印SpringBoot的banner标识
这个其实就是在启动的时候可以修改对应的启动图标
创建对应的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); applyInitializers(context); listeners.contextPrepared(context); bootstrapContext.close(context); if (this .logStartupInfo) { logStartupInfo(context.getParent() == null ); logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments" , applicationArguments); if (printedBanner != null ) { 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 ()); } Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray(new Object [0 ])); listeners.contextLoaded(context); }
其中自动装配是在refresh的阶段实现的