3.1 bean标签的解析及注册
- DefaultBeanDefinitionDocumentReader.parseDefaultElement:解析的标签有四种:import,alias,beans,bean
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
- 首先理解bean的解析,
在默认的processDefaultElement里面处理Bean的definition逻辑如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 根据element获取BeanDefinitionHolder,里面包括着bean的名称,alias数组列表及BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 查看此beanName下面是否存在子的定义,继续再解析一次
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 以下为真正开始注册beanDefinition
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方法,是多态的
- BeanDefinitionParserDelegate当中的parseBeanDefinitionElement首先会解析id和name,以及alias,然后调用真正解析其他属性的parseBeanDefinitionElement方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {}
- BeanDefinitionParserDelegate当中的parseBeanDefinitionElement下面的方法,会真正解析ele里面的Attribute,描述信息,元数据,Look-up,Construct,Qualifier,Property等信息
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {}
- 解析完成之后会返回BeanDefinitionHolder,里面包涵着xml里面定义的bean的所有属性
- 调用BeanDefinitionReaderUtils.registerBeanDefinition方法进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- 对应不同的Register去注册对应的bean信息;
- 由于我是使用xmlbeanFactory的方式去实现,所以注册器会使用DefaultListableBeanFactory
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 是否已经注册
if (oldBeanDefinition != null) {
}else{
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}else{
// private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
}
// 清除缓存信息
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
- 最终会将bean的名称和定义信息放入到ConcurrentHashMap当中
3.2 alias标签解析
- DefaultBeanDefinitionDocumentReader.processAliasRegistration方法解析alias标签并完成注册信息
protected void processAliasRegistration(Element ele) {
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
// 注册alias信息
getReaderContext().getRegistry().registerAlias(name, alias);
}
catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias +
"' for bean with name '" + name + "'", ele, ex);
}
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
- 注册器是SimpleAliasRegistry,继承了AliasRegistry
3.3 import标签解析
import标签示例
<import resource="classpath*:"></import>
<import resource="http:"></import>
<import resource="file:"></import>
- 将import标签当中的resource封装为Resource类,Resource可以包涵classpath,url,file对象
- 解析Resource,判断是相对路径还是绝对路径
- 根据Resource去loadBeanDefinitions
- 加载完成之后,通知监听器
getReaderContext().fireImportProcessed(location, actResArray,
extractSource(ele));
3.4 beans标签解析
beans标签示例
- spring在解析的时候将beans标签定义为NESTED~BEANSELEMENT~=“beans”
- beans标签的属性非常的多,但是肯定是循环去解析,因为beans里面是一个一个的小bean
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);
}
}