框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析
文章目录
- 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定义,比如ConfigurationClassPostProcessor
、XxxBeanPostProcessor
等等!如下图所示:
核心代码如下:
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定义!
注意:
@ComponentScan
扫描的类会被优先注册bean定义@Import
、@ImportResource
导入的类首先被加入到Map中,并延迟注册! 注意:通过@Import可以为容器中导入bean定义,多用于集成其他组件,例如springboot的自动配置,就是用的@Import
导入的多种组件bean定义到容器- 所有的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注解过程:
注意:
@ComponentScan
所扫描到的类(@Component
)会立刻注册成bean
定义- 但是对于
@Bean
、@Import
注解所标注的类,在parser.parse(candidates)
解析时,会先将其放在一个Set
集合中,延迟注册。等到parser.parse(candidates)
方法执行完毕后,在reader.loadBeanDefinitions(configClasses)
方法中进行注册bean定义! - 对于
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-method
,Spring
会尝试使用instantiateUsingFactoryMethod
方法 - 在 xml配置中,可以使用
factory-bean
和factory-method
两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean
返回 - 在注解配置中, 会解析
@Bean
修饰的方法。并将返回结果注入到Spring
容器中。解析时BeanDefinition
的factoryMethodName
正是@Bean
修饰的方法本身。
- 如果
- 使用构造器创建实例
- Spring则打算通过
bean
的构造函数来创建bean
。但是一个bean
可能会存在多个构造函数,这时候Spring会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以Spring
将判断好的构造函数缓存到RootBeanDefinition
中, - 如果缓存中不存在,则进行构造函数的筛选并缓存解析结果。过程如下
- 解析构造函数参数
- 获取候选的构造函数列表
- 解析构造函数参数个数
- 寻找最匹配的构造函数
- 如果无参数传入,则使用无参构造器实例化!
- 使用构造器创建实例,主要两种实例化
SimpleInstantiationStrategy
和CglibSubclassingInstantiationStrategy
,简单实例化策略(直接反射) 和Cglib
动态代理策略(通过cglib
代理),默认第二种。
- Spring则打算通过
- 调用
注意
:如果有两个类型相同的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);}
在第④步调用的是
BeanPostProcessorsBeforeInitialization
的postProcessBeforeInitialization
方法,现在调用的是BeanPostProcessorsAfterInitialization
的postProcessAfterInitialization
方法!
注意:无论是实例化、属性赋值都调用了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
所做的事情!步骤如下:
实例化Bean对象
,这个时候Bean的对象是非常低级的,基本不能够被我们使用,因为连最基本的属性都没有设置,可以理解为 连Autowired注解都是没有解析的;填充属性
,当做完这一步,Bean对象基本是完整的了,可以理解为Autowired注解已经解析完毕,依赖注入完成了;- 如果Bean实现了
BeanNameAware
接口,则调用setBeanName方法; - 如果Bean实现了
BeanClassLoaderAware
接口,则调用setBeanClassLoader方法; - 如果Bean实现了
BeanFactoryAware
接口,则调用setBeanFactory方法; - 调用BeanPostProcessor的
postProcessBeforeInitialization
方法; - 如果Bean实现了
InitializingBean
接口,调用afterPropertiesSet方法; - 如果Bean定义了
init-method
方法,则调用Bean的init-method方法; - 调用BeanPostProcessor的
postProcessAfterInitialization
方法;当进行到这一步,Bean已经被准备就绪了,一直停留在应用的 上下文中,直到被销毁; - 如果应用的上下文被销毁了,如果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不同,其返回的对象不是指定类的一个实例,其返回的是该
FactoryBean
的getObject
方法所返回的对象。使用时需要一个类实现FactoryBean接口,并重写getObject方法。- getObject()方法调用时机:在容器初始化后,我们主动使用getBean获取bean时调用!
4.1 FactoryBean实例的获取过程
我们已经知道,spring创建实例是通过finishBeanFactoryInitialization
的doGetBean
方法去做的,在该方法中会判断bean
是否是FactoryBean
的子类,如果是,则会调用FactoryBean
的getObject()
返回对应实例!
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从加载到初始化过程总结
首先从new AnnotationConfigApplicationContext(MainConfig.class)进入初始化。
在构造器中实例化一个强大的bean工厂
DefaultListableBeanFactory
在构造器中会实例化一个读取器reader,reader中注册了一些spring内部所需要的类,比如
ConfigurationClassPostProcessor
、处理事件的类、处理@Autoworied
的类等。实例化一个扫描器scanner,用于手动扫描包,无关紧要。真正扫描我们系统的bean的其实不是他。
调用
invokeBeanFactoryPostProcessors
方法解析配置类所包含的所有@ConmponentScan、@Import中所涉及的bean,把他们注册成bean定义,放进bean定义池中执行完
invokeBeanFactoryPostProcessors
后,bean定义注册完毕,然后调用finishBeanFactoryInitialization
方法,循环bean定义池,并判断是否符合生产标准,如果符合,就生产bean对象在生产bean之前先从单例池中拿一次bean,没有的话,调用docreatbean方法,通过反射创建bean、填充属性、执行生命周期回调等方式创建一个单例bean,最后放入单例池中。
至此,初始化过程完结!
框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析相关推荐
- 尚硅谷2020最新版宋红康JVM教程-中篇-第3章类的加载过程(类的生命周期)详解-4-过程三:Initialization(初始化)阶段
static与final的搭配问题 初始化阶段,简言之,为类的静态变量赋予正确的初始值. 具体描述 类的初始化是类装载的最后一个阶段.如果前面的步骤都没有问题,那么表示类可以顺利装载到系统中.此时,类 ...
- miniui datagrid 隐藏列默认赋值_「小程序JAVA实战」 小程序默认加载的页面和生命周期(八)...
小程序如何加载的呢?生命周期!源码:https://github.com/limingios/wxProgram.git 中的No.3 加载页面 小程序默认加载的pages中的第一个目录 不管你的名称 ...
- Spring源码解析-applicationContext.xml加载和bean的注册
applicationContext文件加载和bean注册流程 Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...
- 有没有code能改xml内容_Spring源码解析-applicationContext.xml加载和bean的注册
applicationContext文件加载和bean注册流程 Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...
- Spring容器启动流程+Bean的生命周期【附源码】
如果对SpringIoc与Aop的源码感兴趣,可以访问参考:https://javadoop.com/,十分详细. 文章目录 Spring容器的启动全流程 Spring容器关闭流程 Bean 的生命周 ...
- Spring Bean的生命周期以及IOC源码解析
IOC源码这一块太多只能讲个大概吧,建议还是去买本Spring IOC源码解析的书来看比较好,我也是自己看源代码以及视频整理的笔记 Bean的生命周期大概可以分为四个阶段,具体的等会再说,先看看IOC ...
- 28 Java类的加载机制、什么是类的加载、类的生命周期、加载:查找并加载类的二进制数据、连接、初始化、类加载器、双亲委派模型、自定义类加载器
28Java类的加载机制 28.1.什么是类的加载 28.2.类的生命周期 28.2.1.加载:查找并加载类的二进制数据 28.2.2.连接 28.2.3.初始化 28.3.类加载器 28.4.类的加 ...
- 页面加载时,vue生命周期的触发顺序
那么进入某个路由对应的组件的时候,我们会触发哪些类型的周期呢? 根实例的加载相关的生命周期(beforeCreate.created.beforeMount.mounted) 组件实例的加载相关的生命 ...
- spring启动过程之源码跟踪(小结bean的生命周期)--spring Debug
spring in action 1.容器发现bean的定义,初始化bean 2.使用依赖注入的方式,spring根据bean定义,设置bean的所有属性 3.如果bean继承了BeanNameAwa ...
最新文章
- mendix归还界面如何只显示登录人自己借阅的书籍,而不显示全部人借阅的书籍
- 重磅发布:Redis 对象映射框架来了,操作大大简化!
- asp.net 生成下载word的两种方式
- 如何完美隐藏Disposable的存储和销毁过程(二)
- 嵌入式Linux之我行——ARM MMU工作原理剖析
- linux一路填坑...
- Python打包分发工具setuptools简介
- Spring官方都说废掉GuavaCache用Caffeine,你还不换?
- LintCode-- Remove Linked List Elements
- Visual studio 内存不足的解决方案(out of memory)
- [转载] Python字典按照keys排序输出为列表
- oracle 的 父子关系,oracle父子关系树递归排序要注意什么?
- spring boot系列(三)spring boot 配置spring data jpa
- c语言常量指针和指针常量
- Termux:api 使用及脚本分享
- 索尼计算机bios正确设置,索尼vaio笔记本如何进入bios设置_索尼笔记本进入bios图解...
- echarts绘制地图
- hdu1814 暴力
- 为什么黑客用python-《Python绝技》:运用Python成为顶级黑客
- 配备Apple T2 安全芯片的 Mac 机型及T2芯片mac电脑U盘装系统教程
热门文章
- mysql统计姓名为小明_Mysql 统计查询相同字段只统计一条
- html时间框自动更新,原生javascript实现自动更新的时间日期
- sw工程图导出bom_SolidWorks材料明细表自动调用钣金展开尺寸,轻松导出BOM表
- 机器人三定律真有用?但AI可能并不会遵守
- 桌面桌面虚拟化-Vmware horizon 7相关文件共享
- L2-007. 家庭房产
- MongoDB 副本集的相关概念【转】
- Hyper-V虚拟机安装及网卡无法找到,驱动无法安装解决办法
- apache的php扩展名解析漏洞
- 黄聪:Python中的__metaclass__=type什么意思?