一、前言
接下来,我们对 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<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//存放程序员自己添加的实现了BeanDefinitionRegistryPostProcessor的
List<BeanDefinitionRegistryPostProcessor> 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<BeanDefinitionRegistryPostProcessor> 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<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
//alreadyParsed处理过就放到里面
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
把符合条件的类放到 candidates 里面去重后,然后进行解析,解析代码如下,可以根据思维导图看。
parser.parse(candidates);
首先,比较重要的一点,就是把加了 @ComponentScans 注解的类拿出来,进行解析,解析后,会对加了 @ComponentScans 的类进行扫描,在这里,当吧所有的类进行扫描后,还会递归调用 checkConfigurationClassCandidate 方法判断一下是不是上面所提的5种类型。
//处理所有@ComSet<AnnotationAttributes> 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<BeanDefinitionHolder> 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<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//扫描basePackage路径下的java文件
//并把它转成BeanDefinition
Set<BeanDefinition> 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<SourceClass> 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<String, AbstractBeanDefinition> 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:https://github.com/huangliangyun