BeanDefinition
從我的上一篇文章你可以知道滓走,BeanDefinition
定義了一個Bean大概需要什么信息,給這些信息定義了一些getter和setter方法腰懂,作為接口層它不負(fù)責(zé)定義具體的參數(shù),AbstractBeanDefinition
對這個接口進(jìn)行了實現(xiàn),它提供了一個BeanDefinition
所需要具備的基本能力,如果需要擴(kuò)展功能哗蜈,那么可以對這個類進(jìn)行繼承,再添磚加瓦即可。今天我們來看看AbstractBeanDefinition
的三個子類:
- RootBeanDefinition
- ChildBeanDefinition
- GenericBeanDefinition
RootBeanDefinition
從Spring2.5開始,RootBeanDefinition僅作為運行時的BeanDefinition視圖洞翩。如果需要編程定義BeanDefinition稽犁,那么推薦使用GenericBeanDefinition。
Spring的解釋是:GenericBeanDefinition的優(yōu)勢在于骚亿,它允許動態(tài)定義父依賴項已亥,而不是一個以"硬編碼"定義BeanDefinition的角色。
也就是說来屠,bean的一般形式是以GenericBeanDefinition的標(biāo)準(zhǔn)形式存在的陷猫,在特定的時機(jī),會將GenericBeanDefinition轉(zhuǎn)成RootBeanDefinition
RootBeanDefinition特點
- 存儲
BeanDefinitionHolder
對象星虹,該對象用來存儲Bean的name與alias的對應(yīng)關(guān)系,提供BeanDefinition
的訪問方式 -
AnnotatedElement
,這個是Java反射包的注解溶诞,開發(fā)者可以通過它來操作注解讯蒲。如平時常見到的getAnnotation()
、getAnnotations()
弃榨、isAnnotationPresent()
等 -
allowCaching
,是否允許緩存 -
isFactoryMethodUnique
,工廠方法是否唯一 -
targetType
,與Java泛型相關(guān)的工具類 -
resolvedTargetType
,當(dāng)前類持有的Class對象 -
factoryMethodToIntrospect
,緩存工廠方法 -
Executable
,緩存已經(jīng)解析的構(gòu)造函數(shù)或者方法晴股,Executable是Method和Construct的父類 -
constructorArgumentsResolved
,布爾值瞬雹,表示構(gòu)造函數(shù)是否被解析完畢 -
resolvedConstructorArguments
,緩存被完全解析的構(gòu)造函數(shù)參數(shù) -
postProcessed
,是否被MergedBeanDefinitionPostProcessor處理 -
beforeInstantiationResolved
,已啟動實例化前的后處理器 -
externallyManagedInitMethods
,初始化時的回調(diào)函數(shù) -
externallyManagedDestroyMethods
,銷毀時的回調(diào)函數(shù) -
constructorArgumentLock
和postProcessingLock
,對象鎖,有興趣的可以自行深入唬渗。這里不做闡述
此外减江,RootBeanDefinition不可以進(jìn)行setParentName()操作囚霸。
可以看到它存儲了許多關(guān)于注解與反射相關(guān)的信息,這或許會在某些時機(jī)用到這些信息進(jìn)行反射。
Demo
通過Java代碼來實例化一個RootBeanDefinition
Root
public class Root {
private String name;
private String description;
private boolean isRoot;
public Root() {
}
/**
* 構(gòu)造函數(shù)
* @param name 名稱 對應(yīng)的index為 0
* @param description 描述 對應(yīng)的index為 1
* @param isRoot 是否是父BeanDefinition 對應(yīng)的index為 2
*/
public Root(String name, String description, Boolean isRoot) {
this.name = name;
this.description = description;
this.isRoot = isRoot;
}
@Override
public String toString() {
return "Root{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", isRoot=" + isRoot +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean getIsRoot() {
return isRoot;
}
public void setIsRoot(boolean root) {
isRoot = root;
}
}
Child
package com.xjm.model;
/**
* @author jaymin
* 2020/11/29 14:21
*/
public class Child {
private String name;
private String description;
private boolean isRoot;
private String parentName;
public Child(String name, String description, boolean isRoot, String parentName) {
this.name = name;
this.description = description;
this.isRoot = isRoot;
this.parentName = parentName;
}
public Child() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean getIsRoot() {
return isRoot;
}
public void setIsRoot(boolean root) {
isRoot = root;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
@Override
public String toString() {
return "Child{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", isRoot=" + isRoot +
", parentName='" + parentName + '\'' +
'}';
}
}
這里定義的對象待會會復(fù)用店归,我就不重新定義了
RootBeanDefinitionDemo
package com.xjm.bean.definition;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jaymin<br>
* <p>
* 2020/11/29 13:28
*/
@SuppressWarnings("all")
public class RootBeanDefinitionDemo {
/**
* 通過構(gòu)造器注入?yún)?shù)獲取RootBeanDefinition
*
* @return
*/
public static RootBeanDefinition getRootBeanDefinitionByConstruct() {
ConstructorArgumentValues cargs = new ConstructorArgumentValues();
cargs.addIndexedArgumentValue(0, "rootA");
cargs.addIndexedArgumentValue(1, "This is a RootBeanDefinition");
cargs.addIndexedArgumentValue(2, true);
RootBeanDefinition rootBeanDefinitionA = new RootBeanDefinition(Root.class, cargs, null);
return rootBeanDefinitionA;
}
/**
* 通過Setter的方式注入?yún)?shù),返回RootBeanDefinition
*
* @return
*/
public static RootBeanDefinition getRootBeanDefinitionBySetter() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("name", "rootB");
propertyValues.addPropertyValue("description", "This is a RootBeanDefinition");
propertyValues.addPropertyValue("isRoot", true);
RootBeanDefinition rootBeanDefinitionB = new RootBeanDefinition(Root.class, null, propertyValues);
return rootBeanDefinitionB;
}
public static void main(String[] args) {
// 1. 構(gòu)建一個空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 2.創(chuàng)建一個RootBeanDefinition
RootBeanDefinition rootBeanDefinitionA = getRootBeanDefinitionByConstruct();
RootBeanDefinition rootBeanDefinitionB = getRootBeanDefinitionBySetter();
applicationContext.registerBeanDefinition("rootA", rootBeanDefinitionA);
applicationContext.registerBeanDefinition("rootB", rootBeanDefinitionB);
// 這里埋一個點盟步,直到這里才調(diào)用了Root對象的構(gòu)造函數(shù)
applicationContext.refresh();
Root rootA = ((Root) applicationContext.getBean("rootA"));
Root rootB = ((Root) applicationContext.getBean("rootB"));
System.out.println(rootA.toString());
System.out.println(rootB.toString());
}
}
ChildBeanDefinition
支持setParentName(),參數(shù)為父RootBeanDefinition的name,通過構(gòu)造函數(shù)的方式進(jìn)行設(shè)置繼承關(guān)系.Spring的注釋寫到多數(shù)情況下GenericBeanDefinition可以替代ChildBeanDefinition,所以這里就不詳細(xì)講了憋他,提供一個demo供大家品味.
ChildBeanDefinitionDemo
package com.xjm.bean.definition;
import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jaymin<br>
* <p>
* 2020/11/29 14:20
*/
@SuppressWarnings("all")
public class ChildBeanDefinitionDemo {
public static void main(String[] args) {
// 1. 構(gòu)建一個空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
String parentName = "rootB";
String childName = "child";
RootBeanDefinition rootBeanDefinition = RootBeanDefinitionDemo.getRootBeanDefinitionBySetter();
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition(parentName);
childBeanDefinition.setBeanClass(Child.class);
childBeanDefinition.getPropertyValues().addPropertyValue("parentName", parentName);
childBeanDefinition.getPropertyValues().addPropertyValue("isRoot", false);
// 注冊
applicationContext.registerBeanDefinition(parentName, rootBeanDefinition);
applicationContext.registerBeanDefinition(childName, childBeanDefinition);
// 刷新上下文
applicationContext.refresh();
Root root = applicationContext.getBean(Root.class);
Child child = (Child) applicationContext.getBean(childName);
System.out.println(root.toString());
System.out.println(child.toString());
}
}
GenericBeanDefinition
提供了setParentName()的方法,并且是setter的方式牲迫,通過讀Spring的注釋影晓,它如此描述道:
GenericBeanDefinition是一站式商店饵婆,用于標(biāo)準(zhǔn)bean定義。像任何bean定義一樣功偿,它允許指定一個類以及可選的構(gòu)造函數(shù)參數(shù)值和屬性值心傀。另外,可以通過“ parentName”屬性靈活地配置從父bean定義派生的內(nèi)容拆讯。
child
GenericBeanDefinitionDemo
package com.xjm.bean.definition;
import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jaymin
* 2020/11/29 14:57
*/
public class GenericBeanDefinitionDemo {
public static GenericBeanDefinition getRootBeanDefinition() {
GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
rootBeanDefinition.setBeanClass(Root.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("name", "root")
.add("description", "I am a rootBeanDefinition")
.add("isRoot", true);
rootBeanDefinition.setPropertyValues(propertyValues);
return rootBeanDefinition;
}
public static GenericBeanDefinition getChildBeanDefinition() {
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setBeanClass(Child.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("parentName", "root");
childBeanDefinition.setParentName("root");
childBeanDefinition.setPropertyValues(propertyValues);
return childBeanDefinition;
}
public static void main(String[] args) {
// 1. 構(gòu)建一個空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
GenericBeanDefinition rootBeanDefinition = getRootBeanDefinition();
GenericBeanDefinition childBeanDefinition = getChildBeanDefinition();
applicationContext.registerBeanDefinition("root", rootBeanDefinition);
applicationContext.registerBeanDefinition("child", childBeanDefinition);
applicationContext.refresh();
Root root = applicationContext.getBean(Root.class);
Child child = applicationContext.getBean(Child.class);
System.out.println(root.toString());
System.out.println(child.toString());
}
}
可以看到脂男,我們只用了一個GenericBeanDefinition就可以完成RootBeanDefinition和RootBeanDefinition能做到的事情。只需要setParentName()种呐,就可以拷貝另一個BeanDefinition的信息宰翅。易于擴(kuò)展
留給讀者的話
Spring源碼工程非常地龐大,但是提供了大量的注釋陕贮,有的時候光變量就一大堆堕油,我們怎么讓這些東西給我們留下一個深刻的印象呢,唯有實踐加上思考肮之。我個人知識儲量尚未足夠豐富掉缺,只能留下一些代碼,有興趣的朋友可以自行跟著實現(xiàn)一下戈擒,感受一下Spring的強(qiáng)大之處眶明。至于更深層的原理,目前尚未能完全講的透徹筐高。如有不對的地方搜囱,歡迎指正丑瞧。