【Spring Bean 生命周期系列】传送门
1、Spring Bean生命周期: Bean元信息的配置与解析阶段
2、Spring Bean生命周期: Bean的注册
3、Spring Bean生命周期: BeanDefinition的合并过程
写在前面
注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE
前言
书接上文,BeanDefinition注册到IoC容器后,紧接着就是要使用Bean了,要使用必须先要获取Bean,这里我们就以DefaultListableBeanFactory#getBean 方法来引出本次讨论的内容:BeanDefinition的合并
通过前面的章节我们了解到了BeanDefinition,那什么是BeanDefinition的合并呢?为什么要进行合并呢? 带着这个问题,我们到源码中去找找答案。
为了使源码逻辑有个参照,这里先给出一个案例,在分析源码时 将这个案例也代入进去方便我们理解源码
BeanDefinition的合并源码分析
实体类
@Data
public class SuperUser implements Serializable {
private String address;
public SuperUser(String address) {
this.address = address;
}
public SuperUser() {
}
}
@Data
@ToString(callSuper = true)
public class User extends SuperUser {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
基于GenericBeanDefinition注册有层次的Bean
public class GenericBeanDefinitionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
rootBeanDefinition.setBeanClass(SuperUser.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("address", "地址");
rootBeanDefinition.setPropertyValues(propertyValues);
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setBeanClass(User.class);
ConstructorArgumentValues argumentValues = new ConstructorArgumentValues();
argumentValues.addIndexedArgumentValue(0, "我就是我");
argumentValues.addIndexedArgumentValue(1, 18);
childBeanDefinition.setConstructorArgumentValues(argumentValues);
childBeanDefinition.setParentName("superUser");
childBeanDefinition.setPrimary(true);
context.registerBeanDefinition("superUser", rootBeanDefinition);
context.registerBeanDefinition("user", childBeanDefinition);
context.refresh();
User user = context.getBean("user", User.class);
System.out.println(user);
SuperUser superUser = context.getBean("superUser", SuperUser.class);
System.out.println(superUser);
context.close();
}
}
在分析源码时我们要有侧重点,这里会将不太相关的逻辑一带而过。
AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
}
if (mbd.isSingleton()) {
}
else if (mbd.isPrototype()) {
}
else {
}
if (requiredType != null && !requiredType.isInstance(bean)) {
}
return (T) bean;
}
上面的方法实现比较长、比较复杂,这里只对重要的地方进行些注释说明并将与本次讨论无关的代码先行进行注释。
下面就进入到BeanDefinition的合并逻辑了
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
if (bd.getParentName() == null) {
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
分析了上面的源码,我们试着总结一下:
1、如果不存在parentName,即不需要被合并,直接将bd转为RootBeanDefinition 返回即可
2、如果存在parentName
- 先根据parentName 找到父bd,若实体存在多级继承关系,则需要递归地查找。
- 将父bd转为RootBeanDefinition,并将子bd与父bd进行合并
- 设置一些其他属性
总结 看过源码之后我们再来回答下前言部分的问题
原来呀,有些bd就像Java中的继承一样,是有层次关系的。子bd需要复用父bd的属性并覆盖与bd同名的属性,比如上面例子中user与superUser 这两个bd。因此就有了bd的合并。
以上就是本章讨论的主要内容了,如您在阅读过程中发现有错误,还望指出,感谢!
|