前言
上篇博客spring 5.0.x源码学习系列三: AnnotationConfigApplicationContext类的无参构造方法的作用介绍了AnnotationConfigApplicationContext类无参构造方法的作用, 再次回顾下主要有如下几个作用:
- 初始化spring bean工厂
DefaultListableBeanFactory
- 通过
AnnotatedBeanDefinitionReader
将spring6个内置bean以RootBeanDefinition到bean
的类型注册到工厂, 其中要记住最重要的ConfigurationClassPostProcessor
- 初始化
ClassPathBeanDefinitionScan
(这个没啥用, 真正的扫描逻辑并不是用到它) - AnnotationConfigApplicationContext的几个身份:
BeanDefinitionRegistry
和GenericApplicationContext
接下来进入正文: AnnotationConfigApplicationContext类register方法作用
一、项目demo
一、AnnotationConfigApplicationContext类register方法api
- 从上之下的源码就是它的执行过程, 附带注释
// AnnotationConfigApplicationContext.java
/**
* 顾名思义,传入的是被注解的类,并且在里面做了是否存在注解的校验(可以传多个类)
* 根据代码可知: 又是通过AnnotatedBeanDefinitionReader来注册的
*/
public void register(Class>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
// AnnotationConfigApplicationContext.java
/**
* 因为上述api提供的是一个可变参数, 所以此处要遍历注册它
*/
public void register(Class>... annotatedClasses) {
for (Class> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
// AnnotationConfigApplicationContext.java
/**
* 将代码逻辑委托给另外方法
*/
public void registerBean(Class> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
// AnnotationConfigApplicationContext.java
/**
* 由调用链可知,调用此方法时, 只有第一个参数有值,其他的都为null
* @param annotatedClass
* @param instanceSupplier
* @param name
* @param qualifiers
* @param definitionCustomizers
* @param
*/
void doRegisterBean(Class annotatedClass, @Nullable Supplier instanceSupplier, @Nullable String name,
@Nullable Class extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 记住这个创建beanDefinition的api, 很常用。
// 在利用spring扩展点动态添加一些beanDefinition至bean工厂时很有用
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// set进去的为null, 因为传进来的为null
abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 这块用的是当前类默认的beanNameGenerator => AnnotationBeanNameGenerator
// private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 并不会使用到我们自定义的beanNameGenerator, 为什么?
// 因为我们压根就还没解析到@ComponentScan注解(这里需要有一点自定义beanNameGenerator的知识点)
// 大致可以参考我Github中的这个类:
// https://github.com/AvengerEug/spring/blob/develop/ioc/src/main/java/com/eugene/sumarry/ioc/annotationtype/MyBeanNameGenerator.java
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 这里开始处理一些通用的注解: 比如@Lazy、@Primary、@DependsOn、@Role、@Description
// 获取到这些注解中的值, 并填充至传入的AnnotatedGenericBeanDefinition
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 这块如果按照spring的流程来基本上用不上, 因为传入的是null
if (qualifiers != null) {
for (Class extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 传入的也为null, 按照正常流程来, 先忽略它
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 不知道是为了啥, 要new这么一个对象, 可能只是为了方便传值吧 - -!
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 这块暂时不知道。。。
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册beanDefinition, 传入的是registry, 有了上篇博客的基础,
// 易知该registry就是AnnotationConfigApplicationContext
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
// BeanDefinitionReaderUtils.java
/**
* 注册beanDefinition
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 它前面封装了一个definitionHolder, 现在又拆解它......
// 该register是一个AnnotationConfigApplicationContext
// 但此时是调用父类GenericApplicationContext的registerBeanDefinition方法
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
// DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 这里会校验当前的beanDefinition, 具体校验啥没具体看,
// 但beanDefinition instanceof AbstractBeanDefinition条件是成立的
// 因为它(AnnotatedGenericBeanDefinition)继承了AbstractBeanDefinition
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// beanDefinitionMap: 这个属性是bean工厂存放定义的beanDefinition
// 因为要注册beanDefinition, 所以先校验它是否存在, 正常流程中
// 这里基本为null
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isWarnEnabled()) {
logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判断bean是否在创建, 正常的register流程中, 返回的基本为false
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 将beanD注册到bean工厂中,
// 1. 添加到beanDefinitionMap
// 2. 添加到beanDefinitionNames
// 3. 从manualSingletonNames中移除, 这里不清楚manualSingletonNames
// 属性是干啥的, 不过根据名字来猜测: 存放手动创建的单例bean的名字?
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
二、运行结果
三、小结
- Q1: 上面的代码执行完后(register方法执行完毕),往bean工厂中注册了几个beanDefinition, bean工厂中一共有几个beanDefinition?
- A1: 注册了
2
个beanDefinition, 此时bean工厂中一共有6 + 2 = 8
个beanDefinition。
- Q2: 现在bean工厂中存在的beanDefinition的类型总共有几种?分别是?
- A2: 两种。 分别是
RootBeanDefinition
和AnnotatedGenericBeanDefinition
。
- Q3: 现在有bean被创建出来吗?
- A3: 没有, register方法只是注册beanDefinition。 一般是注册一个配置类(eg: 包含@ComponentScan注解的类)方便spring的后续操作(eg: 扫描包解析注解等等)。
- Q4: spring认为描述bean的通用注解有哪些?
- A4: @Lazy、@Primary、@DependsOn、@Role、@Description
- spring源码学习对应GitHub 地址https://github.com/AvengerEug/spring/tree/develop/resourcecode-study
- I am a slow walker, but I never walk backwards.