Spring源碼解析 -- 讀取bean元數據
spring源碼解析 -- 構造bean
spring源碼解析 -- 注入屬性
spring源碼解析 -- Spring Context
Spring源碼解析 -- AOP原理(1)
Spring源碼解析 -- AOP原理(2)
Spring源碼解析 -- SpringMvc原理java
源碼分析基於spring 4.3.xnode
本文經過閱讀源碼,分析spring如何讀取xml配置中的bean元數據。
關於閱讀源碼的思路,可參考 -- 如何閱讀java源碼 spring
本文主要分析XmlBeanFactory,XmlBeanFactory是一個簡單的容器, 從XML文件中讀取配置元數據。安全
BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
複製代碼
XmlBeanFactory已過期,但好在簡單,便於分析源碼。bash
XmlBeanFactory#構造函數 -> XmlBeanDefinitionReader#loadBeanDefinitions -> XmlBeanDefinitionReader#doLoadBeanDefinitions微信
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource); // #1
return registerBeanDefinitions(doc, resource); // #2
}
...
}
複製代碼
#1
加載xml到Document類(使用org.w3c.dom讀取xml文件) #2
registerBeanDefinitions -> 解析xml數據dom
XmlBeanDefinitionReader#registerBeanDefinitionside
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // #1
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // #2
return getRegistry().getBeanDefinitionCount() - countBefore;
}
複製代碼
#1
構建BeanDefinitionDocumentReader
#2
createReaderContext -> 構建ReaderContext,ReaderContext中存放了xml的resource,XmlBeanDefinitionReader等信息,這些後面都要使用。
registerBeanDefinitions -> 使用BeanDefinitionDocumentReader解析xml數據函數
注意,ReaderContext中存放了XmlBeanDefinitionReader,而XmlBeanDefinitionReader中存放了bean註冊器BeanDefinitionRegistry(後面註冊BeanDefinition要使用)。這個註冊器就是XmlBeanFactory,XmlBeanFactory中構建XmlBeanDefinitionReader時將this做爲Registry參數 XmlBeanDefinitionReader#reader源碼分析
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
複製代碼
XmlBeanFactory的父類DefaultListableBeanFactory實現了BeanDefinitionRegistry。
DefaultBeanDefinitionDocumentReader#registerBeanDefinitions -> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) { // #1
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); // #2
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root); // #3
parseBeanDefinitions(root, this.delegate); // #4
postProcessXml(root);
this.delegate = parent;
}
複製代碼
#1
判斷元素的命名空間是否爲spring的beans空間,這個方法後面也有使用
#2
處理PROFILE元素屬性
#3
預處理,爲子類提供的擴展方法
#4
parseBeanDefinitions -> 解析beans元素
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
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); // #1
}
else {
delegate.parseCustomElement(ele); // #2
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
複製代碼
#1
對於beans命名空間的元素,使用默認的方法進行解析
#2
處理非beans命名空間的元素,使用對應的解析器處理
用戶也能夠自定義標籤及標籤解析器。
DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // #1
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // #2
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // #3
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // #4
doRegisterBeanDefinitions(ele);
}
}
複製代碼
#1
解析import元素
#2
解析alias元素
#3
解析bean元素
#4
解析beans元素
主要看對bean元素的解析,DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // #1
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // #2
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); // #3
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); // #4
}
}
複製代碼
#1
根據xmleizo,生成BeanDefinitionHolder
#2
應用NamespaceHandler#decorate擴展方法
#3
將BeanDefinition註冊到spring上下文
#4
發送註冊事件
這裏出現了一個很重要的類BeanDefinition。
BeanDefinition是spring對bean元數據的抽象, 是配置文件中<bean>
元素在spring容器中的內部表示類,存儲了bean的元數據, 如屬性PropertyValues, BeanClassName,Scope等。
BeanDefinitionHolder中持有BeanDefinition實例,以及beanName和aliases屬性。
BeanDefinitionParserDelegat#parseBeanDefinitionElement有幾個重載方法,最終都調用以下方法
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
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);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent); // #1
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // #2
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd); // #3
parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // #4
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // #5
parseConstructorArgElements(ele, bd); // #6
parsePropertyElements(ele, bd); // #7
parseQualifierElements(ele, bd); // #8
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
...
}
複製代碼
#1
使用className和parent建立BeanDefinition
#2
處理scope等元素屬性
#3
處理meta元素屬性
#4
處理lookup-method元素屬性
#5
處理replaced-method元素屬性
#6
處理constructor-arg構造方法參數
#7
處理property元素
#8
處理qualifier元素
看一下如何處理property元素 BeanDefinitionParserDelegate#parsePropertyElements -> BeanDefinitionParserDelegate#parsePropertyElement
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // #1
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName); // #2
PropertyValue pv = new PropertyValue(propertyName, val); // #3
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv); // #4
}
finally {
this.parseState.pop();
}
}
複製代碼
#1
解析屬性名
#2
將xml配置的屬性值轉化爲內部表示類
#3
建立PropertyValue,PropertyValue中name存放屬性名,value存放了xml配置原始值。
#4
添加到BeanDefinition,BeanDefinition使用MutablePropertyValues存放全部的屬性信息。
xml配置原始值並非屬性最終值,而是xml配置在spring中對應的內部表示類,如property元素的value屬性會表示爲TypedStringValue(相似於BeanDefinition表示<bean>
元素)。
BeanDefinitionParserDelegate#parsePropertyValue
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
...
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
if (hasRefAttribute) { // #1
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (hasValueAttribute) { // #2
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
else if (subElement != null) { // #3
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;
}
}
複製代碼
#1
若是property元素存在ref屬性,解析爲RuntimeBeanReference
#2
若是存在value屬性,解析爲TypedStringValue
#3
若是存在子標籤,就解析子標籤。子標籤和spring內部表示類對應以下
子標籤爲bean,解析爲BeanDefinitionHolder
子標籤爲ref,解析爲RuntimeBeanReference
子標籤爲idref,解析爲RuntimeBeanNameReference
子標籤爲value,解析爲TypedStringValue
子標籤爲null,解析爲TypedStringValue
子標籤爲array,解析爲ManagedArray
子標籤爲list,解析爲ManagedList
子標籤爲set,解析爲ManagedSet
子標籤爲map,解析爲ManagedMap
子標籤爲props,解析爲ManagedProperties
回到DefaultBeanDefinitionDocumentReader#processBeanDefinition方法#3
步驟, 看一下如何將BeanDefinition註冊到spring上下文 BeanDefinitionReaderUtils#registerBeanDefinition
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // #1
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias); // #2
}
}
}
複製代碼
#1
使用beanName註冊bean
#2
註冊別名alias
註冊器registry從ReaderContext中獲取,實際就是DefaultListableBeanFactory(注意上文對ReaderContext的說明)。
DefaultListableBeanFactory#registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
...
}
else {
if (hasBeanCreationStarted()) { // #1
synchronized (this.beanDefinitionMap) { // #2
this.beanDefinitionMap.put(beanName, beanDefinition); // #3
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions; // #4
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons; // #5
}
}
}
else { // #6
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
複製代碼
#1
判斷spring是否進入構建bean的階段
#2
beanDefinitionNames/manualSingletonNames不是線程安全類,須要加鎖同步
#3
添加beanDefinition到DefaultListableBeanFactory#beanDefinitionMap
#4
經過寫時複製,添加beanName到DefaultListableBeanFactory#beanDefinitionNames
#5
經過寫時複製,刪除manualSingletonNames的DefaultListableBeanFactory#beanDefinitionNames
#6
還在註冊階段,不須要加鎖同步
最後, 看一下DefaultBeanDefinitionDocumentReader#parseBeanDefinitions方法#2
步驟對非beans空間的xml標籤的處理, BeanDefinitionParserDelegate#parseCustomElement
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); // #1
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)); // #2
}
複製代碼
#1
經過命名空間獲取特定的NamespaceHandler #2
使用NamespaceHandler進行處理
若是您以爲本文不錯,歡迎關注個人微信公衆號,您的關注是我堅持的動力!