一、BeanDefinition介紹
BeanDefinition包含了spring應(yīng)用中各對象屬性以及對象間的相互依賴關(guān)系,Bean對象的創(chuàng)建與依賴注入都是依照BeanDefinition來進行初始化、注入等,就好比Bean創(chuàng)建的配方。

通過上面的屬性可以看到,基本和我們xml里的配置一一對應(yīng)的,它就是我們xml里bean配置的載體。
二、BeanDefinition的裝載

主入口DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
//...............................................................
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
//開始解析document
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//判斷是否是spring 默認的 namespace
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
判斷是否是spring默認的配置文件,具體邏輯見代碼截圖

2.1 spring默認的解析策略
//DefaultBeanDefinitionDocumentReader.parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//import
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//alias
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
DefaultBeanDefinitionDocumentReader.processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//配置文件解析完畢后放到 BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//將BeanDefinition注冊到容器中,也就是我們所說的bean的創(chuàng)建與依賴注入
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
具體的解析邏輯見
BeanDefinitionParserDelegate.parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
//parseState 是一個解析棧,在異常時候方便記錄
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//創(chuàng)建 BeanDefinition,將name和class屬性注入, class是使用XmlReaderContext的classloader,根據(jù)配置加載
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析bean 屬性配置 如 initMethod 這些
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析構(gòu)造方法注入配置
parseConstructorArgElements(ele, bd);
//解析 bean property配置
parsePropertyElements(ele, bd);
//解析 bean qualifier配置
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
//省略若干代碼
finally {
//成功解析后,移除該 BeanEntry
this.parseState.pop();
}
return null;
}
創(chuàng)建beandefinition實現(xiàn)代碼BeanDefinitionReaderUtils.createBeanDefinition
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
//設(shè)置class對象
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
//如果classloader為空則設(shè)置className
bd.setBeanClassName(className);
}
}
return bd;
}
解析 bean property配置parsePropertyElements具體執(zhí)行單元parsePropertyElement,當然如果bean配置沒有property,自然也不會走到parsePropertyElement邏輯
public void parsePropertyElement(Element ele, BeanDefinition bd) {
//..................
//解析property value
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
//...................................
//屬性是否是 ref
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
//屬性是否是 value
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
//...................................
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
//RuntimeBeanReference ref的載體
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (hasValueAttribute) {
//TypedStringValue 普通value的載體
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
//是否還有有子節(jié)點 比如 list,map這些就有子節(jié)點
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
//如果不是spring默認解析繼續(xù)走自定義handler解析
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
//如果節(jié)點是 bean
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
//如果節(jié)點是 ref
else if (nodeNameEquals(ele, REF_ELEMENT)) {
// ......................
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
return parseIdRefElement(ele);
}
//如果節(jié)點是 value
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
return parseValueElement(ele, defaultValueType);
}
//如果節(jié)點是 null
else if (nodeNameEquals(ele, NULL_ELEMENT)) {
// ......................
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
//如果節(jié)點是 array
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
return parseArrayElement(ele, bd);
}
else if (nodeNameEquals(ele, LIST_ELEMENT)) {
return parseListElement(ele, bd);
}
else if (nodeNameEquals(ele, SET_ELEMENT)) {
return parseSetElement(ele, bd);
}
else if (nodeNameEquals(ele, MAP_ELEMENT)) {
return parseMapElement(ele, bd);
}
else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
return parsePropsElement(ele);
}
else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
parsePropertySubElement,解析代碼就不貼了,篇幅有限,我們可以看里面list節(jié)點的解析鏈路
parsePropertySubElement() -> parseListElement() -> parseCollectionElements() -> parsePropertySubElement(),對沒有看錯,最后又回到了 parsePropertySubElement(),不過邏輯分支自然是不同的
public List parseListElement(Element collectionEle, BeanDefinition bd) {
String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes();
//整體被包裝成ManagedList類型
ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
target.setSource(extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(parseMergeAttribute(collectionEle));
//解析list 子節(jié)點值, 集合類的都用該方法進行解析
parseCollectionElements(nl, target, bd, defaultElementType);
return target;
}
其它類型的節(jié)點解析就不一一貼代碼了,只要調(diào)用鏈路清晰后,順著代碼也基本就看明白了
2.2 自定義的解析
如果不是spring默認解析的則有自定的handler進行解析
//BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
this.readerContext.getNamespaceHandlerResolver()也就是XmlReaderContext.namespaceHandlerResolver,這是什么東西呢?我們回到 XmlReaderContext創(chuàng)建的代碼
//XmlBeanDefinitionReader.registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
//createReaderContext(resource) 創(chuàng)建XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected XmlReaderContext createReaderContext(Resource resource) {
if (this.namespaceHandlerResolver == null) {
//這里創(chuàng)建了默認的 NamespaceHandlerResolver
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);
}
如何根據(jù)xml的namespace獲取對應(yīng)的handler?
//DefaultNamespaceHandlerResolver
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
//根據(jù)namespace獲取對應(yīng)的handler
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
//判斷handler是否實現(xiàn)接口NamespaceHandler
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
//如果handler首次加載,那么此時value只是個className
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
//.........?????
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
//..............................
}
}
DefaultNamespaceHandlerResolver.getHandlerMappings
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
這行代碼會將classLoader classpath下的所有META-INF/spring.handlers給加載并存放在 handlerMappings, nameSpaceUri作為key,handler class作為value
以dubbo的spring.handlers為例
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
自定義解析,通過nameSpace找到對應(yīng)的handler,然后由對應(yīng)的handler來解析對應(yīng)的xml,這么一個解析的方式。
三 BeanDefinition 注冊到容器
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
解析
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析后的bean,BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 將解析后的bean,BeanDefinitionHolder注冊到容器
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
執(zhí)行具體動作
BeanDefinitionReaderUtils.registerBeanDefinition -> DefaultListableBeanFactory.registerBeanDefinition
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");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
//注冊到beanDefinitionMap ,啟用synchronized保證整個操作是原子性的,達到數(shù)據(jù)一致性
synchronized (this.beanDefinitionMap) {
//檢查是否已經(jīng)有同名的注冊進來了,如果有則判斷是否允許覆蓋,若不允許則拋異常
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//覆蓋掉beanName對應(yīng)的原BeanDefinition,當然不僅僅是簡單的覆蓋,還需要將已經(jīng)實例化的bean對象銷毀、父類同名的覆蓋等
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
整個過程,所謂的容器注冊,就是以 beanName為key, BeanDefinition為value,存放到beanDefinitionMap
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
PS. ConcurrentHashMap已經(jīng)是線程安全了為什么還加synchronized?
注意觀察synchronized,鎖的塊,spring要保證讀寫一致。ConcurrentHashMap只能保證單個操作的線程安全。
四 結(jié)語
至此,beanDefinition信息已經(jīng)注冊到spring容器中,接下來就可以被容器使用,都在beanDefinitionMap進行檢索,這些信息是容器建議依賴反轉(zhuǎn)的基礎(chǔ)。
源碼版本:3.2.18.RELEASE
系列文章
spring源碼探索(0)-IOC容器-架構(gòu)設(shè)計
spring源碼探索(1)-IOC容器-Resource
spring源碼探索(2)-IOC容器-BeanDefinition加載與注冊
spring源碼探索(3)-IOC容器-Bean的一生
spring源碼探索(4)-AOP實現(xiàn)原理