文章目录

  • 1.BeanFactory和ApplicationContext的区别?
  • 2. IOC与 Bean的加载过程
    • ①:初始化容器DefaultListableBeanFactory
    • ②:创建读取器,初始化spring创世类
    • ③:注册配置类的bean定义
    • ④:refresh()
      • 1. invokeBeanFactoryPostProcessors(beanFactory)
      • 2. finishBeanFactoryInitialization(beanFactory)
  • 3. Bean的生命周期
  • 4. FactoryBean 和 BeanFactory有什么区别?
  • 5. 加不加@Configuration有什么区别?
  • 6. IOC和bean从加载到初始化过程总结

1.BeanFactory和ApplicationContext的区别?

BeanFactory是ApplicationContext的顶级接口,ApplicationContext在前者的基础上又增加了很多扩展点,例如:注解处理,bean扫描和AOP代理等等。和BeanFactory相比更值得推荐。

对于许多扩展容器功能,BeanPostProcessor扩展点是必不可少的。如果仅使用普通的DefaultListableBeanFactory,也就是通过BeanFactory创建bean,默认情况下不会检测到并激活bean后置处理器。 此时的bean只是一个空的bean,属性注入、aop都没有。也就是说BeanFactory只负责生产bean,而ApplicationContext除了生产bean,还能提供很多的扩展功能,更加全面、强大

功能 BeanFactory ApplicationContext
Bean实例化/装配 Yes Yes
集成的生命周期管理 No Yes
自动注册 BeanPostProcessor No Yes
自动注册 BeanFactoryPostProcessor No Yes
便利的 MessageSource 访问 (国际化) No Yes
内置ApplicationEvent 发布机制 No Yes

2. IOC与 Bean的加载过程

我们可以通过 new ApplicattionContext() 去加载spring容器/上下文。通过不同的配置方式又有以下两种加载容器的方式

①:通过xml配置文件 ** new ClassPathXmlApplicationContext**

context = new ClassPathXmlApplicationContext("xml");

②:通过注解@bean等注解 new AnnotationConfigApplicationContext

context = new AnnotationConfigApplicationContext(MainConfig.class);

第一种通过xml配置文件获取的方式,内部的代码是耦合的。也就是说读取器读取配置类、扫描bean对象、注册bean定义这些操作是由上往下写死在代码里的。通过注解方式获取容器思想比较先进,它通过扩展BeanFactory后置处理器并可插拔的方式,也完成了上述功能,并实现了代码解耦!所以就从new AnnotationConfigApplicationContext(MainConfig.class)开始讲ioc的加载过程吧

注意:当使用springboot时,则采用 ServletWebServerApplicationContext() 来加载容器,这种加载方式不改变原有IOC容器的加载过程,只不过在这个基础上做了一些扩展,比如:加载自动配置类,创建Servlet容器。

①:初始化容器DefaultListableBeanFactory

     //加载spring上下文public AnnotationConfigApplicationContext(Class... componentClasses) {//调用无参构造方法,下文会讲this();//把配置类注册成一个Bean定义,并put到ConcurrentHashMap(Bean定义池)中,因为后边要解析这个类this.register(componentClasses);//spring容器刷新接口,bean的加载和销毁都体现了,是最重要的方法this.refresh();}

this()方法会调用无参构造方法,主要有三大步:

  • ①:初始化容器DefaultListableBeanFactory
  • ②:初始化读取器AnnotatedBeanDefinitionReader
  • ③:初始化扫描器ClassPathBeanDefinitionScanner

this() 方法如下:

    public AnnotationConfigApplicationContext() {//在这里会隐式调用父类的构造方法,初始化DefaultListableBeanFactory//初始化读取配置类reader,下文会进行读取。在其内部初始化了一些创世纪的bean定义,是spring内部的类,用于服务其他bean!this.reader = new AnnotatedBeanDefinitionReader(this);//扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的this.scanner = new ClassPathBeanDefinitionScanner(this);}

首先隐式调用父类的构造方法,初始化DefaultListableBeanFactory作为容器

  this.beanFactory = new DefaultListableBeanFactory();

为什么容器要使用DefaultListableBeanFactory呢?可以看一下DefaultListableBeanFactory的继承体系

可以看到为什么选择DefaultListableBeanFactory作为容器了吧!因为DefaultListableBeanFactory在BeanFactory的基础上,有很大提升!

②:创建读取器,初始化spring创世类

接下来回到this()方法的 new AnnotatedBeanDefinitionReader(this)中,他有什么作用呢?在它的内部初始化了很多维持spring功能的最原始的Bean定义,比如ConfigurationClassPostProcessorXxxBeanPostProcessor等等!如下图所示:

核心代码如下:

     Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 创建 ConfigurationClassPostProcessor 的bean定义if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}// 创建 AutowiredAnnotationBeanPostProcessor的bean定义if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// 创建 CommonAnnotationBeanPostProcessor 的bean定义if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// 创建其他 为spring提供基础功能的其他bean定义  省略.....

其中ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口, BeanDefinitionRegistryPostProcessor接口又扩展了BeanFactoryPostProcessor接口, BeanFactoryPostProcessor是Spring的扩展点之一,ConfigurationClassPostProcessor是Spring极为重要的一个类,必须牢牢的记住上面所说的这个类和它的继承关系如下图。

由于ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,所以必会重写BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,重写该方法主要是为了:读取配置类,解析@ComponentScan@Import@ImportResource@Bean等注解,并把他们注册为bean定义,不过该过程是放在bean工厂的后置处理器中去做,通过refresh()方法中的invokeBeanFactoryPostProcessors方法回调的方式去调用!

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {//该方法可以注册bean定义void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

③:注册配置类的bean定义

register方法会把配置类注册成一个Bean定义,并put到ConcurrentHashMap(Bean定义池,此时的池中已有spring的创世类)中,后边要通过refresh()方法中的invokeBeanFactoryPostProcessors方法回调解析。解析其实是分析这个类所带有的元素,比如@Component、@Import所携带的其他元素!这个过程是ConfigurationClassPostProcessor做的!

    public void register(Class... componentClasses) {Assert.notEmpty(componentClasses, "At least one component class must be specified");//可以看到,上文的读取器在这里使用到,读取了配置类this.reader.register(componentClasses);}

继续往下跟源码,会看到

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {String beanName = definitionHolder.getBeanName();//注册bean定义,是在DefaultListableBeanFactory中做的实现registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());String[] aliases = definitionHolder.getAliases();if (aliases != null) {String[] var4 = aliases;int var5 = aliases.length;for(int var6 = 0; var6 < var5; ++var6) {String alias = var4[var6];registry.registerAlias(beanName, alias);}}}

registerBeanDefinition方法如下:

  this.beanDefinitionMap.put(beanName, beanDefinition);
  private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);

可以看到确实把bean定义放入了ConcurrentHashMap(bean定义池中)

④:refresh()

其实到这里,Spring还没有进行扫描,只是实例化了一个工厂,注册了一些内置的Bean和我们传进去的配置类,真正的大头是在第三行代码this.refresh()。这个方法做了很多事情,让我们点开这个方法:

    public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {//1 刷新预处理,和主流程关系不大,就是保存了容器的启动时间,启动标志等this.prepareRefresh();//2 这个方法和主流程关系也不是很大,可以简单的认为,就是把beanFactory取出来而已。XML模式下会在这里读取BeanDefinitionConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//3 还是一些准备工作,添加了两个后置处理器:ApplicationContextAwareProcessor,ApplicationListenerDetector ,//还设置了忽略自动装配 和 允许自动装配的接口,如果不存在某个bean的时候,spring就自动注册singleton bean//还设置了bean表达式解析器等this.prepareBeanFactory(beanFactory);try {    //4 空方法,留给我们做实现,可能以后Spring会进行扩展this.postProcessBeanFactory(beanFactory);//5.执行自定义的BeanFactoryProcessor和内置的BeanFactoryProcessor,并实例化,帮我们扫描到@ComponentScan、@Component等类this.invokeBeanFactoryPostProcessors(beanFactory);/** 6.在生成bean之前需要先注册bean后置处理器* 例如: * AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入) * RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法) * CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。*/this.registerBeanPostProcessors(beanFactory);//7.初始化国际化资源处理器this.initMessageSource();//8.创建事件多播器this.initApplicationEventMulticaster();//9.模板方法,在容器刷新的时候可以自定义逻辑,不同的Spring容器做不同的事情。this.onRefresh();//10.注册监听器,广播early application eventsthis.registerListeners();      //11.循环bean定义池,实例化剩余的单例bean,这里是真正的ioc和bean的加载过程!!!!!this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

refresh方法中有两个非常重要的方法

1. invokeBeanFactoryPostProcessors(beanFactory)

调用BeanFactoryPostProcessor后置处理器的实现类ConfigurationClassPostProcessor,去解析配置类上边的注解,解析完成后扫描配置类上所有的@Import、@ComponentScan等注解所包含的类,通过Component过滤器过滤掉不需要的类后,把有用的类注册成bean定义!
注意:

  1. @ComponentScan扫描的类会被优先注册bean定义
  2. @Import@ImportResource导入的类首先被加入到Map中,并延迟注册! 注意:通过@Import可以为容器中导入bean定义,多用于集成其他组件,例如springboot的自动配置,就是用的@Import导入的多种组件bean定义到容器
  3. 所有的bean定义被存储在一个Map的数据结构中 (key = “bean名字首字母小写,例如userController” , value =userController的bean定义 ),每个对象对应一个bean定义,bean定义包含的属性在AbstractBeanDenifition中,包括Class信息、是否抽象、是否懒加载等等!

invokeBeanFactoryPostProcessors方法核心逻辑:

 public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// 定义了一个Set,装载BeanName,后面会根据这个Set,来判断后置处理器是否被执行过了。Set<String> processedBeans = new HashSet<>();//判断beanFactory是不是BeanDefinitionRegistry的实例,当然肯定是的if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;//定义了两个List:// 一个是regularPostProcessors,用来装载BeanFactoryPostProcessor,一般情况下,这里永远都是空的,只有手动add beanFactoryPostProcessor,这里才会有数据// 一个是registryProcessors,用来装载BeanDefinitionRegistryPostProcessor// 其中BeanDefinitionRegistryPostProcessor扩展了BeanFactoryPostProcessor。List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();//循环传进来的beanFactoryPostProcessors,一般情况下,这里永远都是空的,只有手动add beanFactoryPostProcessor,这里才会有数据for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {//判断postProcessor是不是BeanDefinitionRegistryPostProcessorif (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;//是的话,执行postProcessBeanDefinitionRegistry方法registryProcessor.postProcessBeanDefinitionRegistry(registry);//然后把对象装到registryProcessors里面去registryProcessors.add(registryProcessor);}else {//不是的话,就装到regularPostProcessors。regularPostProcessors.add(postProcessor);}}//定义了一个临时变量:currentRegistryProcessors,用来装载BeanDefinitionRegistryPostProcessor。List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();//是根据类型查到BeanNames,般情况下,只会找到一个,就是ConfigurationAnnotationProcessorString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//断此后置处理器是否实现了PriorityOrdered接口,//如果实现了,把它添加到currentRegistryProcessors这个临时变量中currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//放入processedBeans,代表这个后置处理已经被处理过了。当然现在还没有处理,但是马上就要处理了。。。processedBeans.add(ppName);}}//进行排序,PriorityOrdered是一个排序接口,如果实现了它,就说明此后置处理器是有顺序的,所以需要排序//当然目前这里只有一个后置处理器,就是ConfigurationClassPostProcessor。sortPostProcessors(currentRegistryProcessors, beanFactory);//合并registryProcessors.addAll(currentRegistryProcessors);//在此处回调的currentRegistryProcessors中的ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry方法,//依次解析`@PropertySource`、`@ComponentScan`、`@Import`、`@ImportResource`、`@Bean`等注解,并注册成bean定义invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//清空currentRegistryProcessors,因为currentRegistryProcessors是一个临时变量,已经完成了目前的使命,所以需要清空,当然后面还会用到。currentRegistryProcessors.clear();// 然后处理实现了Ordered接口的BeanDefinitionRegistryPostProcessorpostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// 最后,处理没有实现Ordered接口的BeanDefinitionRegistryPostProcessorboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// 上面的代码是执行子类独有的方法,这里需要再把父类的方法也执行一次invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}//上面处理的是实现了BeanDefinitionRegistryPostProcessor接口的类//下面处理实现了BeanFactoryPostProcessor接口实现类,其过程与上边的类似!找到BeanFactoryPostProcessor实现类的BeanName数组String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// 创建三个集合,用来保存实现了PriorityOrdered、Ordered、以及无实现 三种beanList<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}//如果实现了PriorityOrdered接口,加入到priorityOrderedPostProcessorselse if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}//如果实现了Ordered接口,加入到orderedPostProcessorNameselse if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {//如果既没有实现PriorityOrdered,也没有实现Ordered。加入到nonOrderedPostProcessorNamesnonOrderedPostProcessorNames.add(ppName);}}//分别处理三个数组!// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}

如上就是回调bean工厂后置处理器invokeBeanFactoryPostProcessors的具体逻辑,其中invokeBeanDefinitionRegistryPostProcessors方法中会依次解析@PropertySource@ComponentScan@Import@ImportResource@Bean等注解,并注册成bean定义。

 @Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {//递归处理内部类,一般不会写内部类if (configClass.getMetadata().isAnnotated(Component.class.getName())) {processMemberClasses(configClass, sourceClass, filter);}//处理@PropertySource注解,@PropertySource注解用来加载properties文件for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}//获得ComponentScan注解具体的内容,//ComponentScan注解除了最常用的basePackage之外,还有includeFilters,excludeFilters等Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {//循环处理componentScansfor (AnnotationAttributes componentScan : componentScans) {// 核心方法!执行扫描解析 parse,把扫描出来的放入setSet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// 循环set,判断是否是配置类// 是的话,递归调用parse方法,因为被扫描出来的类,还是一个配置类,有@ComponentScans注解,或者其中有被@Bean标记的方法 等等,所以需要再次被解析。for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}//如果是配置类,有@ComponentScans注解,递归解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// 处理@Import注解,@Import是Spring中很重要的一个注解,// 正是由于它的存在,让Spring非常灵活,不管是Spring内部,还是与Spring整合的第三方技术,都大量的运用了@Import注解// @Import有三种情况:// 1.Import 普通类,将其作为 @Configuration 类// 2.Import ImportSelector,// 3.Import ImportBeanDefinitionRegistrarprocessImports(configClass, sourceClass, getImports(sourceClass), filter, true);// 处理@ImportResource注解AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 处理@Bean的方法,可以看到获得了带有@Bean的方法后,不是马上转换成BeanDefinition,而是先用一个set接收Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// 处理父类的东西if (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}

@Controller、@Service、@Component等注解标注的类是如何被注册成bean定义的?

想要将@Controller@Service@Component等注解标注的类注册成bean定义的,首先要被扫描到!如上代码所示!这些注解的扫描是发生在Spring解析@ComponentScan时触发的!这些注解虽然名字不同,但都继承于@Component注解



进入解析@ComponentScan的核心方法parse():

 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {//可以看到上来就初始化了一个路径扫描器!ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);。。。。。。 //省略

这个路径扫描器ClassPathBeanDefinitionScanner中定义了两种过滤器:

  • 包含过滤器:includeFilters ,可根据注解过滤,必须扫描某些注解
  • 排除过滤器:excludeFilters,可根据注解过滤,使其不扫描@Controller等注解

后续会把扫描到的类与这两个过滤器做匹配,匹配成功的才可以注册bean定义!而在new ClassPathBeanDefinitionScanner初始化扫描器时,默认把@Component注解加入了包含过滤器includeFilters中,所以后续扫描就可以扫描到@Controller@Service@Component等注解标注的类

 protected void registerDefaultFilters() {// 把`@Component`注解加入了包含过滤器`includeFilters `中this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();}

再扫描时会进入findCandidateComponents,寻找候选者类

 public Set<BeanDefinition> findCandidateComponents(String basePackage) {if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {//会进入到这个ifreturn scanCandidateComponents(basePackage);}}

scanCandidateComponents()方法如下:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {//把 传进来的类似 命名空间形式的字符串转换成类似类文件地址的形式,然后在前面加上classpath*://即:com.xx=>classpath*:com/xx/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//根据packageSearchPath,获得符合要求的文件Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();//循环资源for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {//判断资源是否可读,并且不是一个目录try {//metadataReader 元数据读取器,解析resource,也可以理解为描述资源的数据结构MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);//核心逻辑!在isCandidateComponent方法内部会真正执行匹配规则//注册配置类自身会被排除,不会进入到这个ifif (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}//把符合条件的放入结合candidates.add(sbd);}......//省略//返回集合!return candidates;}

核心匹配规则isCandidateComponent()如下:

 protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {//匹配excludeFilters排除过滤器中的类for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return false;}}//匹配 includeFilters 包含过滤器中的类for (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return isConditionMatch(metadataReader);}}return false;}

如何修改bean定义?

我们可以通过实现BeanFactoryPostProcessor来修改bean定义的属性,使类根据我们的要求完成初始化,如下所示

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 获取bean定义GenericBeanDefinition rootBeanDefinition =(GenericBeanDefinition) beanFactory.getBeanDefinition("instA");/*** 修改自动注入模型* 属性默认使用AutoWired自动注入* 下面修改为按照类型自动注入*/rootBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);/*** 修改beanclass,实例化时根据此处设置的class进行实例化*/rootBeanDefinition.setBeanClass(InstD.class);/*** 修改懒加载方式*/rootBeanDefinition.setLazyInit(true);/*** 修改默认调用构造器方式* 以前是默认空参构造器,现在是默认调用带有String参数的构造器*/GenericBeanDefinition genericBeanDefinition =(GenericBeanDefinition) beanFactory.getBeanDefinition("person");ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();constructorArgumentValues.addIndexedArgumentValue(0,"adc");genericBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);}
}

该自定义的bean工厂后置处理器MyBeanFactoryPostProcessor就在invokeBeanFactoryPostProcessors方法中被执行!

类比形象图

        
解析@Import注解过程:

注意:

  1. @ComponentScan所扫描到的类(@Component)会立刻注册成bean定义
  2. 但是对于@Bean@Import注解所标注的类,在parser.parse(candidates)解析时,会先将其放在一个Set集合中,延迟注册。等到parser.parse(candidates)方法执行完毕后,在reader.loadBeanDefinitions(configClasses)方法中进行注册bean定义!
  3. 对于DeferredImportSelector类,则是在最后进行处理的(@Import之后),spring boot加载自动配置类时就用的是DeferredImportSelector类。它在parser.parse(candidates)方法中,处理它的方法:deferredImportSelectorHandler.process()是放在最后执行的!

2. finishBeanFactoryInitialization(beanFactory)

为什么要单独介绍这个方法呢,因为这个方法里边涵盖了bean的加载过程,是本章的重点!他的主要作用是实例化所有剩余的(非懒加载、单例)的bean。比如上文第5个方法invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化。 实例化的过程各种BeanPostProcessor开始起作用。

首先从Bean定义池中拿到所有的bean定义,把bean定义合并成RootBeanDefinition,因为各种bean定义是不一样的,所以要合成统一类型的RootBeanDefinition,方便后续判断,并检验是否是单例、是否抽象、是否是工厂bean等是否符合生产标准,然后执行doGetBean方法创建实例。实例又分两种:

  • 如果是FactoryBean,则通过getObject()方法获取实例,源码会在第4个标题中讲解
  • 如果是普通bean,则通过createBean()方法去创建实例
 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// transformedBeanName: 去掉 & ,获取真正的实例名 ,而不是 “&实例名“,// 注意: “&实例名“ 是用来获取FactoryBean对象本身的,而不是获取FactoryBean的getObject()方法final String beanName = transformedBeanName(name);Object bean;// 从单例池中拿对象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 + "'");}}// 如果是FactoryBean的话,就调用getObject方法获取实例,下文会讲// 如果不是,返回实例本身bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}。。。。。//省略代码try {//合成统一类型的RootBeanDefinitionfinal RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//检查是否抽象checkMergedBeanDefinition(mbd, beanName, args);//检查是否有其他依赖的类String[] dependsOn = mbd.getDependsOn();。。。。。//省略代码try {//这个getSingleton并不是去单例池中获取,而是创建bean的方法Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {//钩子函数创建beanreturn createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}。。。。。//省略代码return (T) bean;}

在这里先来分析普通bean的创建过程,主要是以下代码:

  if (mbd.isSingleton()) {//这个getSingleton并不是去单例池中获取,而是创建bean的方法sharedInstance = this.getSingleton(beanName, () -> {try {//钩子函数创建beanreturn this.createBean(beanName, mbd, args);} catch (BeansException var5) {this.destroySingleton(beanName);throw var5;}});bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

接下来看一下getSingleton方法!

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {。。。。。。  //省略代码//标记为正在创建this.beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = this.suppressedExceptions == null;if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet();}try {//函数接口调用,获取创建的对象,此时调用的lambda式创建的createBean方法singletonObject = singletonFactory.getObject();newSingleton = true;} catch (IllegalStateException var16) {。。。。。  //省略代码

通过singletonFactory.getObject()获取创建的对象,此时调用的lambda式创建的createBean方法,再继续深入doCreateBean方法,这个方法又做了一堆一堆的事情,但是值得开心的事情就是 我们已经找到了我们要寻找的东西了。bean实例的创建分为以下几步:

  • ①:创建实例

    instanceWrapper = createBeanInstance(beanName, mbd, args);//创建bean的实例。核心
    

    创建实例的源码解读!

    创建实例的步骤如下:

    • 调用 Supplier 接口创建实例 - obtainFromSupplier

      • RootBeanDefinition 中设置了 Supplier 则使用 Supplier 提供的bean替代Spring要生成的bean。主要是为了替代工厂方法(包含静态工厂)或者构造器创建对象,但是其后面的生命周期回调不影响。
      • 因为不管是静态工厂还是工厂方法,都需要通过反射调用目标方法创建对象,反射或多或少影响性能,如果不使用反射呢?Supplier就是面向java8函数式接口编程,就是提供一个回调方法,直接调用回调方法即可,不需要通过反射了。主要是考虑反射调用目标方法不如直接调用目标方法效率高。
    • 使用 factory-method 属性创建实例 - instantiateUsingFactoryMethod
      • 如果RootBeanDefinition 中存在 factoryMethodName 属性,或者在配置文件中配置了factory-methodSpring会尝试使用 instantiateUsingFactoryMethod 方法
      • 在 xml配置中,可以使用 factory-beanfactory-method 两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean返回
      • 在注解配置中, 会解析@Bean修饰的方法。并将返回结果注入到Spring容器中。解析时BeanDefinitionfactoryMethodName 正是 @Bean修饰的方法本身。
    • 使用构造器创建实例
      • Spring则打算通过bean的构造函数来创建bean。但是一个bean可能会存在多个构造函数,这时候Spring会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以Spring将判断好的构造函数缓存到RootBeanDefinition 中,
      • 如果缓存中不存在,则进行构造函数的筛选并缓存解析结果。过程如下
        • 解析构造函数参数
        • 获取候选的构造函数列表
        • 解析构造函数参数个数
        • 寻找最匹配的构造函数
      • 如果无参数传入,则使用无参构造器实例化!
      • 使用构造器创建实例,主要两种实例化 SimpleInstantiationStrategyCglibSubclassingInstantiationStrategy,简单实例化策略(直接反射) 和 Cglib 动态代理策略(通过cglib 代理),默认第二种。

注意:如果有两个类型相同的bean

  • spring中:后创建的覆盖先创建的,@Bean覆盖@Component。
  • 而在springboot中:由于在springboot启动时设置了不允许覆盖,所以有多个bean时,会抛异常!
  • ②:加入三级缓存,解决循环依赖

          boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//加入三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}
    
  • ③:填充属性

    populateBean(beanName, mbd, instanceWrapper);//填充属性
    exposedObject = this.initializeBean(beanName, exposedObject, mbd);//aware系列接口的回调
    

    填充属性源码分析!

    属性注入源码中有如下五种方式

    注入方式 变量 变量值
    没有显式配置上装配的方式 AUTOWIRE_NO 0
    beanName进行装配 AUTOWIRE_BY_NAME 1
    type进行装配 AUTOWIRE_BY_TYPE 2
    在构造函数中进行装配 AUTOWIRE_CONSTRUCTOR 3
    通过内省bean类确定适当的自动装配策略,Spring已经将其标注为@Deprecated AUTOWIRE_AUTODETECT 4

    一般以注解的形式(@Autowired,@Bean)注入的属性,都会由bean的后置处理器进行注入,在进行自动装配的过程中,默认按照"byType"的方式进行Bean加载,如果出现无法挑选出合适的Bean的情况,再将属性名与候选Bean名单中的beanName进行对比。当做完这一步,Bean对象基本是完整的了,可以理解为Autowired注解已经解析完毕,依赖注入完成了;

  • ④:回调各种 Aware 接口

    populateBean(beanName, mbd, instanceWrapper);//填充属性
    exposedObject = this.initializeBean(beanName, exposedObject, mbd);//aware系列接口的回调
    

    可以看到在populateBean填充属性方法后边还有一个initializeBean方法,里边主要回调了一些aware接口!如果bean实现了以下三种aware接口,即可在这里执行aware回调逻辑!

    • bean implements BeanNameAware
    • bean implements BeanClassLoaderAware
    • bean implements BeanFactoryAware

    进入initializeBean方法,

     protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//1.回调各种 Aware 接口invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//2.调用 BeanPostProcessorsBeforeInitialization 扩展wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//3.调用实现InitializingBean的afterPropertiesSet方法// 调用xml方式的 bean标签里配置init-mothod属性invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {//4.调用 BeanPostProcessorsAfterInitialization 扩展wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
    

    回调各种 Aware 接口主要是在invokeInitMethods这个方法中回调的

        private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {//1.回调了BeanNameAwareif (bean instanceof BeanNameAware) {((BeanNameAware)bean).setBeanName(beanName);}//2.回调了BeanClassLoaderAwareif (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = this.getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);}}//3.回调了BeanFactoryAwareif (bean instanceof BeanFactoryAware) {((BeanFactoryAware)bean).setBeanFactory(this);}}}
    
  • ⑤:调用 BeanPostProcessorsBeforeInitialization

    if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    

    可以看到第③步的invokeAwareMethods最多只调用了三个Aware,那么其他的Aware在哪里调用呢?在bean后置处理器的BeanPostProcessorsBeforeInitialization方法中调用的

     /*  各种 Aware 接口* @see org.springframework.context.EnvironmentAware* @see org.springframework.context.EmbeddedValueResolverAware* @see org.springframework.context.ResourceLoaderAware* @see org.springframework.context.ApplicationEventPublisherAware* @see org.springframework.context.MessageSourceAware* @see org.springframework.context.ApplicationContextAware* @see org.springframework.context.support.AbstractApplicationContext#refresh()*///ApplicationContextAwareProcessor 实现了 bean后置处理器
    class ApplicationContextAwareProcessor implements BeanPostProcessor {//在postProcessBeforeInitialization 方法中调用各种Aware接口!@Override@Nullablepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){return bean;}// 。。。。。省略代码return bean;}
    }
    

    图示如下:

    当然我们也可以实现bean的后置处理器,重写postProcessBeforeInitialization方法,执行某些业务逻辑

  • ⑥:初始化回调

    invokeInitMethods(beanName, wrappedBean, mbd);
    

    一个bean想要在初始化完成时,做某些操作,有以下三种方法,执行顺序自上向下!

    • 类中某方法加注解@PostConstruct
    • 实现InitializingBean接口,实现afterPropertiesSet方法
    • xml方式,bean标签里配置init-mothod属性,指向类中的方法。
  • ⑦:调用 BeanPostProcessorsAfterInitialization

        if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}
    

    在第④步调用的是BeanPostProcessorsBeforeInitializationpostProcessBeforeInitialization方法,现在调用的是BeanPostProcessorsAfterInitializationpostProcessAfterInitialization方法!

注意:无论是实例化、属性赋值都调用了bean后置处理器,对功能进行增强!

  • ⑦:最后把对象加入一级缓存中

    this.addSingleton(beanName, singletonObject);
    

经过上边的几步,单例对象创建才创建完成!
        
如何自定义一个BeanPostProcessor ?

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {//重写 postProcessBeforeInitialization 方法@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if(beanName.equals("car")) {System.out.println("postProcessBeforeInitialization");}return bean;}//重写 postProcessAfterInitialization方法@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if(beanName.equals("car")) {System.out.println("postProcessAfterInitialization");}return bean;}
}

如果获取car这个类时,就会打印

postProcessBeforeInitialization
postProcessAfterInitialization

3. Bean的生命周期

经过上面的分析,bean的生命周期其实就是finishBeanFactoryInitialization方法中creatBean所做的事情!步骤如下:

  1. 实例化Bean对象,这个时候Bean的对象是非常低级的,基本不能够被我们使用,因为连最基本的属性都没有设置,可以理解为 连Autowired注解都是没有解析的;
  2. 填充属性,当做完这一步,Bean对象基本是完整的了,可以理解为Autowired注解已经解析完毕,依赖注入完成了;
  3. 如果Bean实现了BeanNameAware接口,则调用setBeanName方法;
  4. 如果Bean实现了BeanClassLoaderAware接口,则调用setBeanClassLoader方法;
  5. 如果Bean实现了BeanFactoryAware接口,则调用setBeanFactory方法;
  6. 调用BeanPostProcessor的postProcessBeforeInitialization方法;
  7. 如果Bean实现了InitializingBean接口,调用afterPropertiesSet方法;
  8. 如果Bean定义了init-method方法,则调用Bean的init-method方法;
  9. 调用BeanPostProcessor的postProcessAfterInitialization方法;当进行到这一步,Bean已经被准备就绪了,一直停留在应用的 上下文中,直到被销毁;
  10. 如果应用的上下文被销毁了,如果Bean实现了DisposableBean接口,则调用destroy方法,如果Bean定义了destory-method 声明了销毁方法也会被调用。

其中bean的后置处理器穿插在bean的实例化、属性赋值、初始化回调终,一共发生了9次调用!

4. FactoryBean 和 BeanFactory有什么区别?

  • BeanFactory: Spring的顶层接口,负责生产bean。为具体的IOC容器的实现提供了规范。
  • FactoryBean:Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBeangetObject方法所返回的对象。使用时需要一个类实现FactoryBean接口,并重写getObject方法。
    • getObject()方法调用时机:在容器初始化后,我们主动使用getBean获取bean时调用!

4.1 FactoryBean实例的获取过程

我们已经知道,spring创建实例是通过finishBeanFactoryInitializationdoGetBean方法去做的,在该方法中会判断bean是否是FactoryBean的子类,如果是,则会调用FactoryBeangetObject()返回对应实例!

 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// transformedBeanName: 去掉 & ,获取真正的实例名 ,而不是 “&实例名“,// 注意: “&实例名“ 是用来获取FactoryBean对象本身的,而不是获取FactoryBean的getObject()方法final String beanName = transformedBeanName(name);Object bean;// 从单例池中拿对象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 + "'");}}// 如果是FactoryBean的话,就调用getObject方法获取实例,下文会讲// 如果不是,返回实例本身bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}

在doGetBean()方法中一开始就获取了名称beanName和实例sharedInstance,拿到sharedInstance后,最终会走到getObjectForBeanInstance(),关键部分就在这个方法中,进入方法代码。

  • 如果传入的实例不是FactoryBean 或者 是以 “&” 开头的,说明这个实例不是FactoryBean ,不会调用getObject方法,直接返回实例
  • 否则就会进入getObjectFromFactoryBean,调用getObject方法,获取实例
 protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// Don't let calling code try to dereference the factory if the bean isn't a factory.if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());}}//1. 如果传入的实例不是FactoryBean 或者 是以 “&” 开头的//说明这个实例不是FactoryBean ,不会调用getObject,直接返回if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}//2. 否则就是FactoryBean , 需要调用getObject()Object object = null;if (mbd == null) {//2.2 先从缓存获取object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());// 调用 getObject 方法获取实例object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;}

进入getObjectFromFactoryBean方法中的doGetObjectFromFactoryBean方法:

 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 可以看到确实调用的是 factory.getObject() 获取的实例!object = factory.getObject();}}...... //省略代码//返回调用getObject() 获取到的实例return object;}

4.2 上文中提到的 “&” 的作用是什么?

关于"&" 的作用可以参考BeanFacory接口中的一段注释:

public interface BeanFactory {/*** Used to dereference a {@link FactoryBean} instance and distinguish it from* beans <i>created</i> by the FactoryBean. For example, if the bean named* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}* will return the factory, not the instance returned by the factory.*/String FACTORY_BEAN_PREFIX = "&";

可以看到BeanFactory的第一个属性就是&,上面的一段注释翻译过来就是:

用于解除对FactoryBean实例的引用,并将其与由FactoryBean创建的bean区别开来。例如,如果名为myJndiObject的bean是一个FactoryBean,那么获取&myJndiObject将返回工厂,而不是工厂返回的实例。

意思就是说:从容器获取实例时

  • 加了&,就是获取FactoryBean本身,而非getObject()方法中的对象
  • 不加&,返回的就是getObject()方法中的对象

验证

自定义一个FactoryBean的实现类

@Component
public class MyBean implements FactoryBean {private String message;public MyBean() {this.message = "通过构造方法初始化实例";}@Overridepublic Object getObject() throws Exception {MyBean myBean = new MyBean();myBean.message = "通过FactoryBean.getObject()创建实例";// 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例return myBean;}@Overridepublic Class<?> getObjectType() {return MyBean.class;}public String getMessage() {return message;}
}

测试类中先通过名称获取Bean实例,打印message的内容,再通过 ’&’+名称 获取实例并打印message内容。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {@Autowiredprivate ApplicationContext context;@Testpublic void test() {MyBean myBean1 = (MyBean) context.getBean("myBean");System.out.println("myBean1 = " + myBean1.getMessage());MyBean myBean2 = (MyBean) context.getBean("&myBean");System.out.println("myBean2 = " + myBean2.getMessage());System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));}
}

打印结果

myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false

通过测试我们发现:获取的两个实例打印的message的值不一样,说明获取到的两个对象的引用相同,印证完毕。

4.3 FactoryBean的使用场景?

FactoryBean接口对于Spring框架来说占用重要的地位,用户可以通过实现该接口定制实例化Bean的逻辑。Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。 很多开源项目在集成Spring 时都使用到FactoryBean,比如 MyBatis3 提供 mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean:

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);......
}

另外,阿里开源的分布式服务框架 Dubbo 中的Consumer 也使用到了FactoryBean

5. 加不加@Configuration有什么区别?

  • 如果不加@Configuration注解,那么在@Bean中使用方法的方式调用另一个beanB,就会重复创建beanB,那么这个beanB就是多例了
  • 如果加了@Configuration注解,则会创建cglib动态代理,在@Bean方法中调用beanB时,会先检测一下容器中是否有beanB实例,如果有直接拿来用,保证单例!

Spring为什么不使用jdk动态代理呢?

原因就在于:cglib的方式会重复的去ioc容器中拿到动态代理类,不会产生多例,而jdk动态代理则会重复创建实例,产生多例。cglib动态代理在调用本代理类中的获取beanB的方法时,会采用一种类似路由的方式,再次调用动态代理类,再通过动态代理类调用这个获取beanB的方法。而jdk动态代理不一样,他在调用beanB的方法时,不会重复调用动态代理类。

验证:

创建一个Tank对象

public class Tank {public Tank() {System.out.println("创建一次Tank");}
}

创建一个Car对象

public class Car {private String name;private Tank tank;
}

配置类 把这两个对象注册进容器

@Configuration  //主要是关注这个@Configuration 加与不加的区别
@ComponentScan(basePackages = {"com.tuling.iocbeanlifecicle"})
public class MainConfigCar {@Bean("car")public  Car car(){Car car = new Car();car.setName("奔驰");car.setTank(tank()); //这里通过下面的方法设置一个Tank对象return car;}@Bean("tank")public Tank tank(){Tank tank = new Tank();return tank;}
}

main方法:获取两次car对象,car对象只打印一次,主要关注Tank对象的打印次数

 public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigCar.class);Car car = (Car) context.getBean("car");Car car1 = (Car) context.getBean("car");Object person = context.getBean("person");System.out.println(person);}

运行结果:
如果配置类加@Configuration 打印了:

如果不加@Configuration 打印了:

6. IOC和bean从加载到初始化过程总结

  1. 首先从new AnnotationConfigApplicationContext(MainConfig.class)进入初始化。

  2. 在构造器中实例化一个强大的bean工厂DefaultListableBeanFactory

  3. 在构造器中会实例化一个读取器reader,reader中注册了一些spring内部所需要的类,比如ConfigurationClassPostProcessor、处理事件的类、处理@Autoworied的类等。

  4. 实例化一个扫描器scanner,用于手动扫描包,无关紧要。真正扫描我们系统的bean的其实不是他。

  5. 调用invokeBeanFactoryPostProcessors方法解析配置类所包含的所有@ConmponentScan、@Import中所涉及的bean,把他们注册成bean定义,放进bean定义池中

  6. 执行完invokeBeanFactoryPostProcessors后,bean定义注册完毕,然后调用finishBeanFactoryInitialization方法,循环bean定义池,并判断是否符合生产标准,如果符合,就生产bean对象

  7. 在生产bean之前先从单例池中拿一次bean,没有的话,调用docreatbean方法,通过反射创建bean、填充属性、执行生命周期回调等方式创建一个单例bean,最后放入单例池中。

至此,初始化过程完结!

框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析相关推荐

  1. 尚硅谷2020最新版宋红康JVM教程-中篇-第3章类的加载过程(类的生命周期)详解-4-过程三:Initialization(初始化)阶段

    static与final的搭配问题 初始化阶段,简言之,为类的静态变量赋予正确的初始值. 具体描述 类的初始化是类装载的最后一个阶段.如果前面的步骤都没有问题,那么表示类可以顺利装载到系统中.此时,类 ...

  2. miniui datagrid 隐藏列默认赋值_「小程序JAVA实战」 小程序默认加载的页面和生命周期(八)...

    小程序如何加载的呢?生命周期!源码:https://github.com/limingios/wxProgram.git 中的No.3 加载页面 小程序默认加载的pages中的第一个目录 不管你的名称 ...

  3. Spring源码解析-applicationContext.xml加载和bean的注册

    applicationContext文件加载和bean注册流程 ​ Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...

  4. 有没有code能改xml内容_Spring源码解析-applicationContext.xml加载和bean的注册

    applicationContext文件加载和bean注册流程 ​ Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...

  5. Spring容器启动流程+Bean的生命周期【附源码】

    如果对SpringIoc与Aop的源码感兴趣,可以访问参考:https://javadoop.com/,十分详细. 文章目录 Spring容器的启动全流程 Spring容器关闭流程 Bean 的生命周 ...

  6. Spring Bean的生命周期以及IOC源码解析

    IOC源码这一块太多只能讲个大概吧,建议还是去买本Spring IOC源码解析的书来看比较好,我也是自己看源代码以及视频整理的笔记 Bean的生命周期大概可以分为四个阶段,具体的等会再说,先看看IOC ...

  7. 28 Java类的加载机制、什么是类的加载、类的生命周期、加载:查找并加载类的二进制数据、连接、初始化、类加载器、双亲委派模型、自定义类加载器

    28Java类的加载机制 28.1.什么是类的加载 28.2.类的生命周期 28.2.1.加载:查找并加载类的二进制数据 28.2.2.连接 28.2.3.初始化 28.3.类加载器 28.4.类的加 ...

  8. 页面加载时,vue生命周期的触发顺序

    那么进入某个路由对应的组件的时候,我们会触发哪些类型的周期呢? 根实例的加载相关的生命周期(beforeCreate.created.beforeMount.mounted) 组件实例的加载相关的生命 ...

  9. spring启动过程之源码跟踪(小结bean的生命周期)--spring Debug

    spring in action 1.容器发现bean的定义,初始化bean 2.使用依赖注入的方式,spring根据bean定义,设置bean的所有属性 3.如果bean继承了BeanNameAwa ...

最新文章

  1. mendix归还界面如何只显示登录人自己借阅的书籍,而不显示全部人借阅的书籍
  2. 重磅发布:Redis 对象映射框架来了,操作大大简化!
  3. asp.net 生成下载word的两种方式
  4. 如何完美隐藏Disposable的存储和销毁过程(二)
  5. 嵌入式Linux之我行——ARM MMU工作原理剖析
  6. linux一路填坑...
  7. Python打包分发工具setuptools简介
  8. Spring官方都说废掉GuavaCache用Caffeine,你还不换?
  9. LintCode-- Remove Linked List Elements
  10. Visual studio 内存不足的解决方案(out of memory)
  11. [转载] Python字典按照keys排序输出为列表
  12. oracle 的 父子关系,oracle父子关系树递归排序要注意什么?
  13. spring boot系列(三)spring boot 配置spring data jpa
  14. c语言常量指针和指针常量
  15. Termux:api 使用及脚本分享
  16. 索尼计算机bios正确设置,索尼vaio笔记本如何进入bios设置_索尼笔记本进入bios图解...
  17. echarts绘制地图
  18. hdu1814 暴力
  19. 为什么黑客用python-《Python绝技》:运用Python成为顶级黑客
  20. 配备Apple T2 安全芯片的 Mac 机型及T2芯片mac电脑U盘装系统教程

热门文章

  1. mysql统计姓名为小明_Mysql 统计查询相同字段只统计一条
  2. html时间框自动更新,原生javascript实现自动更新的时间日期
  3. sw工程图导出bom_SolidWorks材料明细表自动调用钣金展开尺寸,轻松导出BOM表
  4. 机器人三定律真有用?但AI可能并不会遵守
  5. 桌面桌面虚拟化-Vmware horizon 7相关文件共享
  6. L2-007. 家庭房产
  7. MongoDB 副本集的相关概念【转】
  8. Hyper-V虚拟机安装及网卡无法找到,驱动无法安装解决办法
  9. apache的php扩展名解析漏洞
  10. 黄聪:Python中的__metaclass__=type什么意思?