博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
精通 Spring 源码 (二) | 揭秘 Bean 的前世今生
阅读量:4104 次
发布时间:2019-05-25

本文共 16390 字,大约阅读时间需要 54 分钟。

一、前言

接下来,我们对 Bean 的扫描与注册进行探究,一个 Java 类是如何变成一个 Bean 的呢,它中间走过了怎样的历程,这就是我们本章所要讨论的问题。

二、源码分析

在进行分析前,各位胖友可以先看一下思维导图,该思维导图详细记录了源码的每一步流程,并且每一步都有详细的注释,在在线地址可以看到注释,如下:

本次我们将对 refresh 方法进行分析,在这个方法里面有 12 个方法,分别做了不同的事,我们将一步一步进行揭秘。

在这里插入图片描述

1、prepareRefresh

这个方法包括准备工作,设置启动时间,是否激活标识位(容器是否可用),初始化属性源配置,不是很重要。

2、obtainFreshBeanFactory

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

准备工作,初始化Bean工厂,得到 beanFactory, DefaultListableBeanFactory 实现了 ConfigurableListableBeanFactory 严格来说,Bean 生命周期的开始。

3、prepareBeanFactory

prepareBeanFactory(beanFactory);

准备 Bean 工厂,Bean 声明周期的开始,下面是在这个方法里面做的一些重要的事。

//类加载器beanFactory.setBeanClassLoader(getClassLoader());//bean的表达式解释器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//Property和String的转化beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.//Spring 添加一个后置处理器,能够在bean中获得各种Aware (重要)beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

在这里添加了一个后置处理器 new ApplicationContextAwareProcessor(this),如果一个类实现了各种 Aware,就会拥有相对应的功能,这是对 Spring 进行扩展的方式。我们可以看一下,这个后置处理器中的一个非常重要的方法。

比如这个代码 instanceof ApplicationContextAware,一个 Bean 实现了 ApplicationContextAware这个接口,提供setter 方法,就能得到 applicationContext ,这就是真个Spring 环境,我们就可以在代码中动态注册和改变一个 Bean 的属性。

private void invokeAwareInterfaces(Object bean) {		if (bean instanceof Aware) {			if (bean instanceof EnvironmentAware) {				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());			}			if (bean instanceof EmbeddedValueResolverAware) {				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);			}			if (bean instanceof ResourceLoaderAware) {				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);			}			if (bean instanceof ApplicationEventPublisherAware) {				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);			}			if (bean instanceof MessageSourceAware) {				((MessageSourceAware) bean).setMessageSource(this.applicationContext);			}			//当一个对象实现了ApplicationContextAware对象只需要提供setter就能得到applicationContext			if (bean instanceof ApplicationContextAware) {				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);			}		}	}

4、postProcessBeanFactory

这是一个空方法,Spring 后期可能会做扩展。

5、invokeBeanFactoryPostProcessors

重要的方法,实现了 Bean 的扫描与注册。

我们可以跟进这个方法,首先定义了两个 集合,具体作用注释给出了。

//存放程序员自己添加的实现了BeanFactoryPostProcessor的List
regularPostProcessors = new ArrayList<>();//存放程序员自己添加的实现了BeanDefinitionRegistryPostProcessor的List
registryProcessors = new ArrayList<>();

注意一个关键词,程序员自己添加的,何为自己添加,也就是自己定义一个类,然后实现 BeanFactoryPostProcessor 或者 BeanDefinitionRegistryPostProcessor 这两个接口,然后调用下面方法添加进去,加@Component 不算。

//自定义的后置处理器//applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());

紧接着,就会处理 实现了 BeanDefinitionRegistryPostProcessor 的类,调用 postProcessBeanDefinitionRegistry 这个方法,然后把 实现了 BeanFactoryPostProcessor 的类放到一个集合里面去。这里并没有处理。

PS: BeanFactoryPostProcessor 是 BeanDefinitionRegistryPostProcessor 的父类。

for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {					BeanDefinitionRegistryPostProcessor registryProcessor =							(BeanDefinitionRegistryPostProcessor) postProcessor;					//处理					registryProcessor.postProcessBeanDefinitionRegistry(registry);					registryProcessors.add(registryProcessor);				}				else {					regularPostProcessors.add(postProcessor);				}			}

然后又定义了一个集合,存放Spring自己定义的 BeanDefinitionRegistryPostProcessor。

//currentRegistryProcessors Spring内部自己实现这个接口的对象List
currentRegistryProcessors = new ArrayList<>();

通过类型的到自己定义的 BeanDefinitionRegistryPostProcessor,然后放到 currentRegistryProcessors 里面去。

我们可以知道这里只有一个类,也就是 ConfigurationClassPostProcessor ,前面一章我们讲到的创世纪的类,是在最开始的时候注册到 BeanDefinition 里面去的。

String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {					//在这里注册了					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));					processedBeans.add(ppName);				}			}

然后执行所有实现了 BeanDefinitionRegistryPostProcessor 的类。

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

我们点进去,他会执行 ConfigurationClassPostProcessor 这个类的 postProcessBeanDefinitionRegistry 这个方法。具体我们可以看一下思维导图。

在这里插入图片描述

首先会得到容器中已经注册的 BeanDefinition ,然后进行判断是否为以下三个条件。

String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {			BeanDefinition beanDef = registry.getBeanDefinition(beanName);			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {				if (logger.isDebugEnabled()) {					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);				}			}			//判断是不是5种类型类,添加到list中			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));			}		}

1)isFullConfigurationClass

判断 BeanDefinition 的属性是不是 FULL。

2)isLiteConfigurationClass

判断 BeanDefinition 的属性是不是 LITE。

3)checkConfigurationClassCandidate

判断类是否有相关注解,并设置相关的属性 FULL 或 LITE,如果是 加了 @Configuration 注解就设置为 FULL,否则就看看看是不是以下四个注解,如果是就设置为 LITE,并放到集合中去。

static {	candidateIndicators.add(Component.class.getName());	candidateIndicators.add(ComponentScan.class.getName());	candidateIndicators.add(Import.class.getName());	candidateIndicators.add(ImportResource.class.getName());}
//可能有多个配置类重复了Set
candidates = new LinkedHashSet<>(configCandidates);//alreadyParsed处理过就放到里面Set
alreadyParsed = new HashSet<>(configCandidates.size());

把符合条件的类放到 candidates 里面去重后,然后进行解析,解析代码如下,可以根据思维导图看。

parser.parse(candidates);

首先,比较重要的一点,就是把加了 @ComponentScans 注解的类拿出来,进行解析,解析后,会对加了 @ComponentScans 的类进行扫描,在这里,当吧所有的类进行扫描后,还会递归调用 checkConfigurationClassCandidate 方法判断一下是不是上面所提的5种类型。

//处理所有@ComSet
componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately //扫描普通类,componentScan = com.javahly.xxx //扫描@Component Set
scannedBeanDefinitions = //解析,真正解析扫描包 this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } //检查扫描出的类是否有@Configuration并设置FULL和LITE if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }

进入上面代码中的 parse 方法,我们可以看到,这里 new 了一个 ClassPathBeanDefinitionScanner 对包进行扫描,也就是实际扫描的是这里的ClassPathBeanDefinitionScanner ,而不是上一章的初始化时的 ClassPathBeanDefinitionScanner。

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,      componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

然后调用 doScan 方法进行扫描包

protected Set
doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set
beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { //扫描basePackage路径下的java文件 //并把它转成BeanDefinition Set
candidates = findCandidateComponents(basePackage); //拿出对象 for (BeanDefinition candidate : candidates) { //解析scope属性 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { //ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);(findCandidateComponents) //如果这个类是AbstractBeanDefinition的子类 //则为他设置默认值,如lazy,init,destroy postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } //检查并且处理常用注解 //这里的处理主要是把常用注解的值设置到AnnotatedBeanDefinition当中 //当前这个类必须是AnnotatedBeanDefinition类型,也就是加了注解的类 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); //put到Map registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions;}

最后,把扫描出来的类转化为 BeanDefinition 后,设置属性后,就放到了一个 Map 里面。

this.beanDefinitionMap.put(beanName, beanDefinition);

至此,普通的已经完成注册了,紧接着,就会处理加了 @Import 注解的类

processImports(configClass, sourceClass, getImports(sourceClass), true);
for (SourceClass candidate : importCandidates) {   //是不是ImportSelector   if (candidate.isAssignable(ImportSelector.class)) {      // Candidate class is an ImportSelector -> delegate to it to determine imports      //得到这个类      Class
candidateClass = candidate.loadClass(); //反射一个对象 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { //回调 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection
importSourceClasses = asSourceClasses(importClassNames); //递归,Import的类本身有没有被Import //看返回的这个数组中的类是不是有@Import,有就处理,没有就放到Map里面 //importSourceClasses 判断这个类是哪一种Import processImports(configClass, currentSourceClass, importSourceClasses, false); } } //是不是ImportBeanDefinitionRegistrar else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class
candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class //Import普通类 //否则,加入importStack,调用processConfigurationClass处理 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); }}

@import 的类型可能有三种,处理方式如下

ImportSelector 先把这个类放到 configurationClasses中 ,然后再注册

ImportBeanDefinitionRegistrar 放到 importBeanDefinitionRegistrars, 然后再注册

Import普通类 先把这个类放到 configurationClasses中,然后再注册

当扫描完成后,就会进行一些验证

parser.validate();

然后,就会调用以下方法注册,@Bean,Xml,Import 的 Bean,至此,所有的 Bean 就完成了注册。

this.reader.loadBeanDefinitions(configClasses);

至此,就解析完成了 实现 BeanDefinitionRegisterPostProcessor 的类,然后就会执行实现了 BeanFactoryPostProcessors 的类,也就是 BeanDefinitionRegisterPostProcessor 的父类 。

在这里插入图片描述

invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

点进去,这是也是执行 ConfigurationClassPostProcessor 类的 postProcessBeanFactory 方法,里面执行这么一个方法,产生 CGLIB 代理。

enhanceConfigurationClasses(beanFactory);

得到所有的 BeanDefinition 看看有没有全注解类,也就是前面设置了 FULL 的类,加了 @Configuration 的类,如果有,就给这个类添加 CGLIB 动态代理,并添加属性 添加属性 &&beanFactory。

for (String beanName : beanFactory.getBeanDefinitionNames()) {   BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);   //判断是否是一个全注解类   //full和lite   if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {      if (!(beanDef instanceof AbstractBeanDefinition)) {         throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +               beanName + "' since it is not stored in an AbstractBeanDefinition subclass");      }      else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {         logger.warn("Cannot enhance @Configuration bean definition '" + beanName +               "' since its singleton instance has been created too early. The typical cause " +               "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +               "return type: Consider declaring such methods as 'static'.");      }      configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);   }}if (configBeanDefs.isEmpty()) {   // nothing to enhance -> return immediately   return;}
//不加@Configuration不会进这个方法		ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();		for (Map.Entry
entry : configBeanDefs.entrySet()) { AbstractBeanDefinition beanDef = entry.getValue(); // If a @Configuration class gets proxied, always proxy the target class beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); try { // Set enhanced subclass of the user-specified bean class Class
configClass = beanDef.resolveBeanClass(this.beanClassLoader); if (configClass != null) { //完成cglib动态代理 Class
enhancedClass = enhancer.enhance(configClass, this.beanClassLoader); if (configClass != enhancedClass) { if (logger.isDebugEnabled()) { logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " + "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); } } } catch (Throwable ex) { throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } }
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";

为什么要添加动态代理,因为如果不加动态带来,当我们使用 @Bean 声明一个 Bean时,如果在一个@Bean方法里面调用另一个 @Bean 方法,就会产生两个实例,违背了单例原则,添加了代理类后,首先会进行判断,如果容器里面有这个 Bean,他就会调用 $$beanFactory 去直接 get,而不是又 new 一个。

三、结语

最后我们来总结一下比较重要的流程:

首先我们进入 refresh 方法里面,会调用 12 个方法(这里先讲前 5 个)

第一个 prepareRefresh 方法,这里进行一些准备工作;

第二个 obtainFreshBeanFactory 这里得到之前实例化的工厂;

第三个 prepareBeanFactory,这里对 beanFactory 进行一些简单的初始化工作;

第四个 postProcessBeanFactory 空方法;

第五个 invokeBeanFactoryPostProcessors,也是最重要的方法之一,在这个方法里面,会对实现了 BeanDefinitionRegistryPostProcessors 和 BeanFactoryPostProcessors 的类进行解析,其中包括我们自己定义的,也包括 Spring 内置的。

解析的顺序是先解析 BeanDefinitionRegistryPostProcessors ,再解析BeanFactoryPostProcessors。

这里会解析 Spring 内置的非常很重要的一个类,ConfigurationClassPostProcessor ,

首先会执行 postProcessBeanDefinitionRegistry 方法,在这里,会判断已经注册的类是不是加了@Configuration,如果是,就设置一个值为 FULL,不是就判断是不是其余四种,并设置为 LITE,并对加了 @ComponentScan 的类进行扫描,然后还会递归判断扫描出来的类是不是加了 @Configuration,以及还会判断扫描出来的类是普通类(加了 @Component的),还是加了@Import,的,然后进行相对应的注册。

然后会执行 BeanFactoryPostProcess 的 postProcessBeanFactory 方法,这里会判断有没有 FULL 类型的类,如果有,就添加 CGLIB 动态代理,作用是,当我们使用 @Bean 声明一个 Bean时,如果在一个@Bean方法里面调用另一个 @Bean 方法,就会产生两个实例,违背了单例原则,添加了代理类后,首先会进行判断,如果容器里面有这个 Bean,他就会调用 $$beanFactory 去直接 get,而不是又 new 一个。

为了更加直观的展现源码的调用过程,我绘制了一张思维导图!

为了更加直观的展现源码的调用过程,我绘制了一张思维导图!
为了更加直观的展现源码的调用过程,我绘制了一张思维导图!

ABOUT

公众号:【星尘Pro】

github:

推荐阅读

转载地址:http://qdfsi.baihongyu.com/

你可能感兴趣的文章
过滤器及JSP九大隐式对象
查看>>
软件(项目)的分层
查看>>
菜单树
查看>>
MySQL-分布式架构-MyCAT
查看>>
设计模式六大原则(6):开闭原则
查看>>
阿里面试总结--JAVA
查看>>
Servlet的生命周期
查看>>
JAVA八大经典书籍,你看过几本?
查看>>
《读书笔记》—–书单推荐
查看>>
【设计模式】—-(2)工厂方法模式(创建型)
查看>>
有return的情况下try catch finally的执行顺序(最有说服力的总结)
查看>>
String s1 = new String("abc"); String s2 = ("abc");
查看>>
JAVA数据类型
查看>>
Xshell 4 入门
查看>>
SoapUI-入门
查看>>
Oracle -常用命令
查看>>
JAVA技术简称
查看>>
ORACLE模糊查询优化浅谈
查看>>
2016——个人年度总结
查看>>
2017——新的开始,加油!
查看>>