溫馨提示:如果您是剛接觸spring源碼不久,建議您先閱讀BeanDefinitino的前兩篇博文才能更好的理解本篇博文
? ? ? ?書接上回。

? ? ? ?上回咱們講了BeanDefinition的父接口及父接口實現(xiàn)類。本篇博文咱么繼續(xù)講BeanDefinition的實現(xiàn)類。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。
1. AbstractBeanDefinition
? ? ? ?AbstractBeanDefinition是抽象類,它是眾多子類的父類。前兩篇文章講的BeanDefinition屬性值大都保存在AbstractBeanDefinition,并實現(xiàn)了子BeanDefinition通用方法。同時它也繼承了BeanMetadataAttributeAccessor完成attribute和source的操作。我們看一下它的關(guān)鍵源碼:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 此處省略靜態(tài)變量以及final變量
@Nullable
private volatile Object beanClass;
/**
* bean的作用范圍,對應(yīng)bean屬性scope
*/
@Nullable
private String scope = SCOPE_DEFAULT;
/**
* 是否是抽象,對應(yīng)bean屬性abstract
*/
private boolean abstractFlag = false;
/**
* 是否延遲加載,對應(yīng)bean屬性lazy-init
*/
private boolean lazyInit = false;
/**
* 自動注入模式,對應(yīng)bean屬性autowire
*/
private int autowireMode = AUTOWIRE_NO;
/**
* 依賴檢查,Spring 3.0后棄用這個屬性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
/**
* 用來表示一個bean的實例化依靠另一個bean先實例化,對應(yīng)bean屬性depend-on
*/
@Nullable
private String[] dependsOn;
/**
* autowire-candidate屬性設(shè)置為false,這樣容器在查找自動裝配對象時,
* 將不考慮該bean,即它不會被考慮作為其他bean自動裝配的候選者,
* 但是該bean本身還是可以使用自動裝配來注入其他bean的
*/
private boolean autowireCandidate = true;
/**
* 自動裝配時出現(xiàn)多個bean候選者時,將作為首選者,對應(yīng)bean屬性primary
*/
private boolean primary = false;
/**
* 用于記錄Qualifier,對應(yīng)子元素qualifier
*/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
@Nullable
private Supplier<?> instanceSupplier;
/**
* 允許訪問非公開的構(gòu)造器和方法,程序設(shè)置
*/
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一種寬松的模式解析構(gòu)造函數(shù),默認為true,
* 如果為false,則在以下情況
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 拋出異常,因為Spring無法準(zhǔn)確定位哪個構(gòu)造函數(shù)程序設(shè)置
*/
private boolean lenientConstructorResolution = true;
/**
* 對應(yīng)bean屬性factory-bean,用法:
* <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
* <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
*/
@Nullable
private String factoryBeanName;
/**
* 對應(yīng)bean屬性factory-method
*/
@Nullable
private String factoryMethodName;
/**
* 記錄構(gòu)造函數(shù)注入屬性,對應(yīng)bean屬性constructor-arg
*/
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
/**
* 普通屬性集合,就是存放你業(yè)務(wù)類的屬性的地方
*/
@Nullable
private MutablePropertyValues propertyValues;
/**
* 方法重寫的持有者,記錄lookup-method、replaced-method元素
*/
@Nullable
private MethodOverrides methodOverrides;
/**
* 初始化方法,對應(yīng)bean屬性init-method
*/
@Nullable
private String initMethodName;
/**
* 銷毀方法,對應(yīng)bean屬性destroy-method
*/
@Nullable
private String destroyMethodName;
/**
* 是否執(zhí)行init-method,程序設(shè)置
*/
private boolean enforceInitMethod = true;
/**
* 是否執(zhí)行destroy-method,程序設(shè)置
*/
private boolean enforceDestroyMethod = true;
/**
* 是否是用戶定義的而不是應(yīng)用程序本身定義的,創(chuàng)建AOP時候為true,程序設(shè)置
*/
private boolean synthetic = false;
/**
* 定義這個bean的應(yīng)用,APPLICATION:用戶,INFRASTRUCTURE:完全內(nèi)部使用,與用戶無關(guān),
* SUPPORT:某些復(fù)雜配置的一部分
* 程序設(shè)置
*/
private int role = BeanDefinition.ROLE_APPLICATION;
/**
* bean的描述信息
*/
@Nullable
private String description;
/**
* 這個bean定義的資源
*/
@Nullable
private Resource resource;
}
? ? ? ?操作方法我就不列出來了,主要就是對屬性的設(shè)置和獲取,類似于getter和setter方法,讀者自行閱讀。總之,AbstractBeanDefinition 就是保存了屬性值并對屬性值進行設(shè)置和讀取。記住這一點就行了。當(dāng)然,有的讀者說,源碼很簡單,但是里面的屬性值具體代表啥意思呢?在什么時候用到呢?前兩篇博文我說了,我講解BeanDefinition這塊內(nèi)容就是讓大家純粹的理解BeanDefition的作用,BeanDefition是整個spring源碼中的基礎(chǔ)。在以后的學(xué)習(xí)中,BeanDefinition中的屬性值作用會慢慢的浮出水面,大家不要著急。
? ? ? ?AbstractBeanDefinition 其實已經(jīng)涵蓋了所有屬性了,spring為什么要提供這么多的子類?正所謂,既生瑜何生亮!筆者認為,完全可以用一個AbstractBeanDefinition 代替所有的子類,只不過spring為了模塊化,不同的BeanDefinition可能從代碼角度來講都一樣,但是從設(shè)計角度來講我們要模塊化,要拆分,不通模塊的BeanDefinition無論從設(shè)計還是功能肯定有差異,我們當(dāng)然可以將這些差異規(guī)避在AbstractBeanDefinition ,但是這不利于維護和擴展,更不利于閱讀理解。
我們看一下ChildBeanDefinition源碼中的類注解:
* <p><b>NOTE:</b> Since Spring 2.5, the preferred way to register bean
* definitions programmatically is the {@link GenericBeanDefinition} class,
* which allows to dynamically define parent dependencies through the
* {@link GenericBeanDefinition#setParentName} method. This effectively
* supersedes the ChildBeanDefinition class for most use cases.
百度翻一下:

? ? ? ?意思就是說,spring2.5以后GenericBeanDefinition是首選的,也就是說spring2.5以前的版本根本就沒有GenericBeanDefinition這個類。spring總得向前發(fā)展啊,更重要的是盡可能的保持向下兼容呀!其實,RootBeanDefinition也有這種類似的注解,你不信你去看源碼!現(xiàn)如今,我們已經(jīng)不使用ChildBeanDefinition了,完全北GenericBeanDefinition給替代了,但是還在使用RootBeanDefinition。
? ? ? ?Root,Child根據(jù)字面意思,好像是父子關(guān)系,AbstractBeanDefinition 中有個屬性叫abstract(是否是抽象類),抽象類無法實例化呀,不能保存到beanDefinitionMap容器中??!有存在的意義嗎?
? ? ? ?有,模板!如果一個BeanDefinition中的屬性abstract為true,它是讓spring來繼承它,而不是實例化它。
? ? ? ?舉個例子吧:
//業(yè)務(wù)類
public class InterService {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//設(shè)置為抽象類
root.setAbstract(true);
root.setDescription("我是一個模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源碼之路");
//注冊,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child繼承root
ChildBeanDefinition child = new ChildBeanDefinition("interService");
//注冊,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((InterService)context.getBean("child")).getName());
}
}
打印結(jié)果:

? ? ? ?這里講一下這行代碼:
root.getPropertyValues().add("name","源碼之路");
? ? ? ?上文AbstractBeanDefinition 源碼中有一個MutablePropertyValues類型的屬性叫propertyValues,我在注釋中是這么寫的:
/**
* 普通屬性集合,就是存放你業(yè)務(wù)類的屬性的地方
*/
@Nullable
private MutablePropertyValues propertyValues;
? ? ? ?什么意思呢?propertyValues只能保存你業(yè)務(wù)類的屬性,比如業(yè)務(wù)類InterService中有個name屬性, root.getPropertyValues().add("name","源碼之路");在后期spring實例化過程中,會將propertyValues中的屬性值一一對應(yīng)的賦值給業(yè)務(wù)對象。等同于xml文件中的配置:
<bean id="index" class="com.InterService" >
<property name="name" value="源碼之路"></property>
</bean>
? ? ? ?如果,我設(shè)置了一個業(yè)務(wù)類中不存在的屬性,就會報錯,比如:


? ? ? ?我說過,AbstractBeanDefinition中的屬性以后都會講到,別急,這個propertyValues只到啥意思了吧?
? ? ? ?繼續(xù),再添加一個業(yè)務(wù)類:
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//設(shè)置為抽象類
root.setAbstract(true);
root.setDescription("我是一個模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源碼之路");
//注冊,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child繼承root
ChildBeanDefinition child = new ChildBeanDefinition("interService");
child.setBeanClass(User.class);
//注冊,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
}
}
? ? ? ?我們只是增加了child.setBeanClass(User.class);這行代碼
? ? ? ?打印結(jié)果:

? ? ? ?也就是說User類相當(dāng)于繼承了InterService類,等同于xml文件:
<bean id="index" class="com.InterService" >
<property name="name" value="源碼之路"></property>
</bean>
<bean id="user" class="com.User" parent="index">
</bean>
這里很繞,筆者當(dāng)時為了弄懂這里也是費了好大的勁。多讀兩遍就理解了。
2. GenericBeanDefinition
上文我們說GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,我們測試一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
//模板BeanDefinition
GenericBeanDefinition root = new GenericBeanDefinition();
//設(shè)置為抽象類
root.setAbstract(true);
root.setDescription("我是一個模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源碼之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注冊,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child繼承root
GenericBeanDefinition child = new GenericBeanDefinition();
child.setParentName("interService");
child.setAbstract(false);
child.setBeanClass(User.class);
//注冊,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}
? ? ? ?打印結(jié)果:

? ? ? ?我們閱讀下GenericBeanDefinition源碼:
public class GenericBeanDefinition extends AbstractBeanDefinition {
//父BeanDefinition名字
@Nullable
private String parentName;
/**
* Create a new GenericBeanDefinition, to be configured through its bean
* properties and configuration methods.
* @see #setBeanClass
* @see #setScope
* @see #setConstructorArgumentValues
* @see #setPropertyValues
* 構(gòu)造方法,所有屬性均為空
*/
public GenericBeanDefinition() {
super();
}
/**
* Create a new GenericBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
* 從一個給定的BeanDefinition中將屬性值copy給新的GenericBeanDefinition
*/
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
//設(shè)置父類名稱
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//獲取父類名稱
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//根據(jù)當(dāng)前GenericBeanDefinition克隆一個新的GenericBeanDefinition
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new GenericBeanDefinition(this);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof GenericBeanDefinition)) {
return false;
}
GenericBeanDefinition that = (GenericBeanDefinition) other;
return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Generic bean");
if (this.parentName != null) {
sb.append(" with parent '").append(this.parentName).append("'");
}
sb.append(": ").append(super.toString());
return sb.toString();
}
}
3. RootBeanDefinition
? ? ? ?但是,RootBeanDefinition卻不可以替換ChildBeanDefinition
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//設(shè)置為抽象類
root.setAbstract(true);
root.setDescription("我是一個模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源碼之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注冊,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child繼承root
RootBeanDefinition child = new RootBeanDefinition();
child.setParentName("interService");
child.setBeanClass(User.class);
//注冊,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}

? ? ? ?為什么?我們看child.setParentName("interService")這行代碼的源碼:
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
? ? ? ?看到了吧,你設(shè)置父類的時候spring給你拋異常,不允許。RootBeanDefinition的所有構(gòu)造函數(shù)也不給你提供一個設(shè)置父類的參數(shù)。那么問題來了,spring為什么這么做?筆者構(gòu)建好了spring源碼,然后筆者把RootBeanDefinition的源碼改了:
首先,在RootBeanDefinition增加一個parentName的屬性
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
.....
//父類名稱
private String parentName;
....
{
其次,修改setParentName
@Override
public void setParentName(@Nullable String parentName) {
// if (parentName != null) {
// throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
// }
this.parentName = parentName;
}
最后修改getParentName方法,注意,spring原來的就是return null;
@Override
public String getParentName() {
// return null;
return this.parentName;
}
打印結(jié)果:

? ? ? ?此時,RootBeanDefinition充當(dāng)了ChildBeanDefinition的角色。留作業(yè),spring為什么這么做?不要告訴我setParentName拋異常所以不允許,我已經(jīng)證明該源碼可以了,我問的是spring源碼作者他當(dāng)時咋想的?我給你打個樣:這里涉及到bean合并。
? ? ? ?最后讀下RootBeanDefinition的源碼吧:
public class RootBeanDefinition extends AbstractBeanDefinition {
//BeanDefinitionHolder存儲有Bean的名稱、別名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通過它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允許緩存
boolean allowCaching = true;
//從字面上理解:工廠方法是否唯一
boolean isFactoryMethodUnique = false;
//封裝了java.lang.reflect.Type,提供了泛型相關(guān)的操作,具體請查看:
// ResolvableType 可以專題去了解一下子,雖然比較簡單 但常見
@Nullable
volatile ResolvableType targetType;
//緩存class,表明RootBeanDefinition存儲哪個類的信息
@Nullable
volatile Class<?> resolvedTargetType;
//緩存工廠方法的返回類型
@Nullable
volatile ResolvableType factoryMethodReturnType;
/** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object();
//緩存已經(jīng)解析的構(gòu)造函數(shù)或是工廠方法,Executable是Method、Constructor類型的父類
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明構(gòu)造函數(shù)參數(shù)是否解析完畢
boolean constructorArgumentsResolved = false;
//緩存完全解析的構(gòu)造函數(shù)參數(shù)
@Nullable
Object[] resolvedConstructorArguments;
//緩存待解析的構(gòu)造函數(shù)參數(shù),即還沒有找到對應(yīng)的實例,可以理解為還沒有注入依賴的形參
@Nullable
Object[] preparedConstructorArguments;
/** Common lock for the two post-processing fields below */
final Object postProcessingLock = new Object();
//表明是否被MergedBeanDefinitionPostProcessor處理過
boolean postProcessed = false;
//在生成代理的時候會使用,表明是否已經(jīng)生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;
//實際緩存的類型是Constructor、Field、Method類型
@Nullable
private Set<Member> externallyManagedConfigMembers;
//InitializingBean中的init回調(diào)函數(shù)名——afterPropertiesSet會在這里記錄,以便進行生命周期回調(diào)
@Nullable
private Set<String> externallyManagedInitMethods;
//DisposableBean的destroy回調(diào)函數(shù)名——destroy會在這里記錄,以便進行生命周期回調(diào)
@Nullable
private Set<String> externallyManagedDestroyMethods;
//===========方法(只例舉部分)
// 由此看出,RootBeanDefiniiton是木有父的
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
// 拿到class類型
@Nullable
public Class<?> getTargetType() {
if (this.resolvedTargetType != null) {
return this.resolvedTargetType;
}
ResolvableType targetType = this.targetType;
return (targetType != null ? targetType.resolve() : null);
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}
}
? ? ? ?可以看到許多與反射相關(guān)的對象,這說明spring底層采用的是反射機制。
? ? ? ?總結(jié)一下,RootBeanDefiniiton保存了以下信息:
? ? ? ?1. 定義了id、別名與Bean的對應(yīng)關(guān)系(BeanDefinitionHolder)
? ? ? ?2. Bean的注解(AnnotatedElement)
? ? ? ?3. 具體的工廠方法(Class類型),包括工廠方法的返回類型,工廠方法的Method對象
? ? ? ?4. 構(gòu)造函數(shù)、構(gòu)造函數(shù)形參類型
? ? ? ?5. Bean的class對象
? ? ? ?可以看到,RootBeanDefinition與AbstractBeanDefinition是互補關(guān)系,RootBeanDefinition在AbstractBeanDefinition的基礎(chǔ)上定義了更多屬性,初始化Bean需要的信息基本完善
4. ChildBeanDefinition
? ? ? ?ChildBeanDefinition不能獨立存在,他必須繼承一個父類,為什么?我們看源碼:
public class ChildBeanDefinition extends AbstractBeanDefinition {
//父類名稱
@Nullable
private String parentName;
/**
* Create a new ChildBeanDefinition for the given parent, to be
* configured through its bean properties and configuration methods.
* @param parentName the name of the parent bean
* @see #setBeanClass
* @see #setScope
* @see #setConstructorArgumentValues
* @see #setPropertyValues
* 構(gòu)造函數(shù),必須設(shè)置一個父類
*/
public ChildBeanDefinition(String parentName) {
super();
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent.
* @param parentName the name of the parent bean
* @param pvs the additional property values of the child
* 構(gòu)造函數(shù),設(shè)置父類和業(yè)務(wù)類屬性
*/
public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
super(null, pvs);
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent.
* @param parentName the name of the parent bean
* @param cargs the constructor argument values to apply
* @param pvs the additional property values of the child
* 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性
*/
public ChildBeanDefinition(
String parentName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent,
* providing constructor arguments and property values.
* @param parentName the name of the parent bean
* @param beanClass the class of the bean to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
* 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類beanClass,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性
*/
public ChildBeanDefinition(
String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClass(beanClass);
}
/**
* Create a new ChildBeanDefinition for the given parent,
* providing constructor arguments and property values.
* Takes a bean class name to avoid eager loading of the bean class.
* @param parentName the name of the parent bean
* @param beanClassName the name of the class to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
* 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類名稱,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性
*/
public ChildBeanDefinition(
String parentName, String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClassName(beanClassName);
}
/**
* Create a new ChildBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
* 構(gòu)造函數(shù),從另一個ChildBeanDefinition進行屬性copy
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super(original);
}
//設(shè)置父類名稱
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//獲取父類名稱
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//校驗,會發(fā)現(xiàn),如果沒有父類就會報錯
@Override
public void validate() throws BeanDefinitionValidationException {
super.validate();
if (this.parentName == null) {
throw new BeanDefinitionValidationException("'parentName' must be set in ChildBeanDefinition");
}
}
//生成一個新的ChildBeanDefinition,并進行屬性值復(fù)制
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new ChildBeanDefinition(this);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ChildBeanDefinition)) {
return false;
}
ChildBeanDefinition that = (ChildBeanDefinition) other;
return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
}
@Override
public String toString() {
return "Child bean with parent '" + this.parentName + "': " + super.toString();
}
}
? ? ? ?ChildBeanDefinition所有的構(gòu)造方法都要求設(shè)置父類名稱,所以從代碼角度講,它必須依賴于父類存在,不能單獨存在。spring官方當(dāng)初設(shè)置ChildBeanDefinition的初衷就是永遠讓它作為一個子bd存在。但是它現(xiàn)在完全可以被GenericBeanDefinition替代了。
我們來做個總結(jié)吧:
- RootBeanDefinition作為父bd出現(xiàn),不能作為子bd出現(xiàn)。
- ChildBeanDefinition必須作為子bd出現(xiàn)。
- GenericBeanDefinition可以作為父bd出現(xiàn),也可以作為子bd出現(xiàn)。他可以完全替代ChildBeanDefinition,但不能完全替代RootBeanDefinition,這一點在以后的bean合并博文中會講解,盡請期待。
5. AnnotatedBeanDefinition
? ? ? ?現(xiàn)如今,大家都用spring注解掃描的方式進行開發(fā),首先在業(yè)務(wù)類上添加一個注解,比如@Service、@Controller、@Component等,spring掃描所有類并判斷是否加入相關(guān)注解,有注解的類會生成一個BeanDefinition并添加到IOC容器中。我們稱注解BeanDefinition。
? ? ? ?AnnotatedBeanDefinition是一個注解bd的接口,可以獲取BeanDefinition注解相關(guān)數(shù)據(jù)。它有兩個實現(xiàn)類ConfigurationClassBeanDefinition、ScannedGenericBeanDefinition和AnnotatedGenericBeanDefinition。
? ? ? ?AnnotatedBeanDefinition接口源碼很容易理解:
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
* 獲取注解信息
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
* @return the factory method metadata, or {@code null} if none
* @since 4.1.1
* 獲取此beanDefinition的工廠方法的元數(shù)據(jù)(如果有)。
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
? ? ? ?這兩個方法是在子類中實現(xiàn)的,我們先查看這兩個方法返回的具體信息:
//業(yè)務(wù)類
@Component
@Description("業(yè)務(wù)類")
@Scope("singleton")
public class InterService {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//測試類
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
context.refresh();
ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) context.getBeanDefinition("interService");
//查看spring給我生成的具體BeanDefinition類型
System.out.println(beanDefinition.getClass().getSimpleName());
//獲取注解信息
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
//獲取工廠方法元數(shù)據(jù)
MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();
System.out.println();
}
}
? ? ? ?測試結(jié)果:

? ? ? ?你就理解為存儲了業(yè)務(wù)類的注解信息,便于spring后續(xù)的解析。
6. ScannedGenericBeanDefinition
? ? ? ?有@Component注解的類,會生成ScannedGenericBeanDefinition類型的Bean定義。注意其它繼承了@Component的注解如@Service、@Controller、@Repository也是生成ScannedGenericBeanDefinition類型的Bean定義。
? ? ? ?ScannedGenericBeanDefinition實現(xiàn)了AnnotatedBeanDefinition接口且繼承了GenericBeanDefinition類,scan翻譯成中文就是掃描的意思,顧名思義,它就是spring掃描后生成的BeanDefinition。它的源碼也很容易理解,讀者自行查閱。
7.AnnotatedGenericBeanDefinition
? ? ? ? AnnotatedGenericBeanDefinition在兩種地方會使用。spring啟動時會生成一個AnnotatedBeanDefinitionReader讀取器:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());
System.out.println();
}
}
public AnnotationConfigApplicationContext() {
//在IOC容器中初始化一個 注解bean讀取器AnnotatedBeanDefinitionReader
this.reader = new AnnotatedBeanDefinitionReader(this);
//在IOC容器中初始化一個 按類路徑掃描注解bean的 掃描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- 解析配置類
主要看這行代碼:
context.register(Config.class);
查看以下源碼:context.register(Config.class)->this.reader.register(componentClasses);->registerBean(componentClass);->doRegisterBean(beanClass, null, null, null);->doRegisterBean,最后跟到doRegisterBean方法:
//第一行代碼
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
.......中間省略........
//最后一行代碼,注冊到IOC容器
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
看到了碼,spring將你的配置定生成了一個AnnotatedGenericBeanDefinition。
我們來測試一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("config").getClass().getSimpleName());
System.out.println();
}
}
打印結(jié)果:
AnnotatedGenericBeanDefinition
- 手動注冊
其實就跟上面配置類一樣。我們不讓spring自動掃描,我們手動注冊一個業(yè)務(wù)類。
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
context.refresh();
//手動注冊一個業(yè)務(wù)類
context.register(InterService.class);
System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());
System.out.println();
}
}
打印結(jié)果:
AnnotatedGenericBeanDefinition
總結(jié):通過AnnotatedBeanDefinitionReader手動注冊的類sping都會生成AnnotatedGenericBeanDefinition。而自動掃描的都會生成ScannedGenericBeanDefinition。
8.ConfigurationClassBeanDefinition
? ? ? ?首先需要注意的是,ConfigurationClassBeanDefinition是一個內(nèi)部類,其外部類是ConfigurationClassBeanDefinitionReader,這個類負責(zé)將@Bean注解的方法轉(zhuǎn)換為對應(yīng)的ConfigurationClassBeanDefinition類,源碼就不過多解釋了,和之前幾個BeanDefinition差不多。
默認設(shè)置
如果@Bean注解沒有指定bean的名字,默認會用方法的名字命名bean。
@Configuration注解的類會成為一個工廠類,而所有的@Bean注解的方法會成為工廠方法,通過工廠方法實例化Bean,而不是直接通過構(gòu)造函數(shù)初始化。
@Bean注解注釋的類會使用構(gòu)造函數(shù)自動裝配。
//在@Configuration注解的類中,使用@Bean注解實例化的Bean,其定義會用ConfigurationClassBeanDefinition存儲。
@Configuration
public class ConfigurationTest {
@Bean
public User getUser(){
return new User();
}
}
public class User {
private String name;
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注冊配置類
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("getUser").getClass().getSimpleName());
}
}

? ? ? ?至此,BeanDefinition整個家族繼承關(guān)系講完了,相信認真讀過這三篇博文的讀者對BeanDefinition都有深入的理解了,建議讀者結(jié)合這三篇博文認真練習(xí),BeanDefinition打好基礎(chǔ)了后續(xù)spring源碼的閱讀才會游刃有余,否則很難讀下去。
? ? ? ?筆者相信,BeanDefinition中的很多屬性大家都不是很理解在spring中到底起了什么作用,這個沒關(guān)系,在后續(xù)源碼學(xué)習(xí)過程中這些屬性的作用會慢慢浮出水面,到時候再回過頭復(fù)習(xí)才會恍然大糊涂。