SpringIOC源码解析(三)-解析xml文件中的bean
概要
- BeanDefinitionReader
- XmlBeanDefinitionReader
- Spring对xml文件解析
BeanDefinitionReader
什么是BeanDefinitionReader?
用来读取BeanDefinition读取器
* Simple interface for bean definition readers. * Specifies load methods with Resource and String location parameters.
主要方法
public interface BeanDefinitionReader {
//返回Bean工厂以向其注册Bean定义。
BeanDefinitionRegistry getRegistry();
/**返回资源加载器以用于资源位置。可以检查ResourcePatternResolver接口并进行相应的转换,以针对给定的 资源模式加载多个资源。
一个null返回值表明,绝对资源加载不适用于这个bean定义阅读器。
这主要用于从bean定义资源中导入其他资源,例如,通过XML bean定义中的“ import”标记。但是,建议相对 于定义资源应用此类导入;只有明确的完整资源位置才会触发绝对资源加载。
**/
@Nullable
ResourceLoader getResourceLoader();
//返回用于Bean类的类加载器。
@Nullable
ClassLoader getBeanClassLoader();
//返回BeanNameGenerator用于匿名Bean(未指定显式Bean名称)。
BeanNameGenerator getBeanNameGenerator();
//从指定的资源加载bean定义。
int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;
//从指定的资源位置加载bean定义。
//该位置也可以是位置模式,前提是此bean定义读取器的ResourceLoader是ResourcePatternResolver。
int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}
XmlBeanDefinitionReader
XmlBeanDefinitionReader是用于对xml文件进行解析,形成BeanDefinition信息。
* Bean definition reader for XML bean definitions. * Delegates the actual XML document reading to an implementation
Spring对xml文件解析
调用解析位置
AbstractApplicationContext#refresh#obtainFreshBeanFactory
public void refresh() throws BeansException, IllegalStateException {
...
* 1、创建BeanFactory对象
* 2、xml解析
* 传统标签解析:bean、import等
* 自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
* 自定义标签解析流程:
* a、根据当前解析标签的头信息找到对应的namespaceUri
* b、加载spring所有jar中的spring.handlers文件。并建立映射关系
* c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
* d、调用类的init方法,init方法是注册了各种自定义标签的解析类
* e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
*
* 3、把解析出来的xml标签封装成BeanDefinition对象
* */
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
...
}
obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//核心方法
refreshBeanFactory();
return getBeanFactory();
}
refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException {
//如果BeanFactory不为空,则清除BeanFactory和里面的实例
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//BeanFactory 实例工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//设置是否可以循环依赖 allowCircularReferences
//是否允许使用相同名称重新注册不同的bean实现.
customizeBeanFactory(beanFactory);
//解析xml,并把xml中的标签封装成BeanDefinition对象
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
- 这里我们重点关注loadBeanDefinitions方法
loadBeanDefinitions
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//创建xml的解析器,这里是一个委托模式
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
//这里传一个this进去,因为ApplicationContext是实现了ResourceLoader接口的
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
//主要看这个方法
loadBeanDefinitions(beanDefinitionReader);
}
- 这里new了一个 XmlBeanDefinitionReader,用于委托对xml文件的处理。将beanFactory传入是为了持有BeanDefinitionRegistry对象,用于注册解析出的BeanDefinition
- 我们重点loadBeanDefinitions的另一个重载方法
loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//获取需要加载的xml配置文件
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
-
getConfigLocations()
用于获取配置文件路径,此路径设置为new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
传入的路径。 -
reader.loadBeanDefinitions(configLocations)
最终会调用到XmlBeanDefinitionReader#loadBeanDefinitions
,下面我们将分析此loadBeanDefinitions
loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
...
//获取Resource对象中的xml文件流对象
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
//InputSource是jdk中的sax xml文件解析对象
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//主要看这个方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
...
}
- 我们调用
new ClassPathXmlApplicationContext()
可以传入多个路径形成路径数组,该路径数组的每个元素会在调用该方法的方法中作为参数循环调用此方法 doLoadBeanDefinitions(inputSource, encodedResource.getResource())
此处最主要方法
doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//把inputSource 封装成Document文件对象,这是jdk的API
Document doc = doLoadDocument(inputSource, resource);
//主要看这个方法,根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
int count = registerBeanDefinitions(doc, resource);
...
...
}
doLoadDocument
将数据Document文件对象registerBeanDefinitions
根据解析出来的document对象,拿到里面的标签元素封装成BeanDefinition
registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//又来一记委托模式,BeanDefinitionDocumentReader委托这个类进行document的解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//主要看这个方法,createReaderContext(resource) XmlReaderContext上下文,封装了XmlBeanDefinitionReader对象
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
-
documentReader
此处为XmlBeanDefinitionReader
委托BeanDefinitionDocumentReader
进行document的解析 -
createReaderContext(resource)
创建了XmlReaderContext
。该对象持有XmlBeanDefinitionReader
和NamespaceHandlerResolver
-
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
//主要看这个方法,把root节点传进去
doRegisterBeanDefinitions(doc.getDocumentElement());
}
-
设置readerContext
-
doRegisterBeanDefinitions(doc.getDocumentElement())
把root节点传进去
doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
...
preProcessXml(root);
//主要看这个方法,标签具体解析过程
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
-
createDelegate(getReaderContext(), root, parent)
创建BeanDefinitionParserDelegate
委托,用于解析具体的Bean内容。 -
BeanDefinitionDocumentReader
委托给BeanDefinitionParserDelegate
进行解析Bean的具体内容。 -
parseBeanDefinitions(root, this.delegate)
具体解析过程。
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);
}
else {
//自定义标签解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
- 我们重点关注默认标签解析
parseDefaultElement
parseDefaultElement
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析document,封装成BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
...
//完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
...
}
BeanDefinitionDocumentReader
调用委托对象的parseBeanDefinitionElement
方法将xml元素委托给BeanDefinitionParserDelegate
进行具体的解析Bean内容BeanDefinitionReaderUtils.registerBeanDefinition
注册解析出的BeanDefinition
parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
//检查beanName是否重复
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//<bean>标签解析的核心方法
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
-
形如
<bean id="car" class="cn.xie.xml.CarFactory" name="BWM,Benz" .../> 解析出的
beanName
以id
属性为主,如果id
属性为空,则为name
属性,如果name
属性解析出多个(xml中name
以,
隔开)以第一个为主。 -
parseBeanDefinitionElement
标签解析的核心方法 -
解析完标签返回
BeanDefinitionHolder
持有beanDefinition
,beanName
,aliases
parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//创建GenericBeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析bean中的meta标签
parseMetaElements(ele, bd);
//解析bean中的lookup-method标签
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析bean中的replaced-method标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean中的constructor-arg标签
parseConstructorArgElements(ele, bd);
//解析bean中的property标签
parsePropertyElements(ele, bd);
//可以不看
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);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
-
createBeanDefinition(className, parent)
创建GenericBeanDefinition对象 -
将各个标签依次解出并设置到BeanDefinition中
-
解析完标签返回BeanDefinition
registerBeanDefinition
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
//完成BeanDefinition的注册,重点看,重要程度 5
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//建立别名和 id的映射,这样就可以根据别名获取到id
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
registerBeanDefinition
将BeanDefinition
注册进BeanDefinitionRegistry
(具体由DefaultListableBeanFactory
实现)。registerAlias
将aliases
注册进AliasRegistry
(具体由SimpleAliasRegistry
实现)。
registerBeanDefinition
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** Map of bean definition objects, keyed by bean name. */
//beanDefinitionMap缓存
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
//beanDefinitionNames
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
//把beanDefinition缓存到map中
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
//把beanName放到beanDefinitionNames list中,这个list着重记住,bean实例化的时候需要用到
this.beanDefinitionNames.add(beanName);
...
}
}
registerAlias
public class SimpleAliasRegistry implements AliasRegistry {
/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
@Override
public void registerAlias(String name, String alias) {
synchronized (this.aliasMap) {
...
this.aliasMap.put(alias, name);
...
}
}
}
}
The End
至此完结!!!