上编文章咱们已经把工厂容器准备好了,那么既然是容器就会存放数据,它是怎么存放的呢?
上一篇传送门
咱们先看下bean定义信息的类关系
loadBeanDefinitions 目前咱们先看 普通 bean定义信息加载
这个方法调用比较深,过渡流程
- AbstractXmlApplicationContext.loadBeanDefinitions 创建bean定义信息的读取器
- AbstractXmlApplicationContext.loadBeanDefinitions(beanDefinitionReader)使用读取器进行加载bean的定义信息
- AbstractBeanDefinitionReader.loadBeanDefinitions 循环多个*.xml文件,进行加载
- AbstractBeanDefinitionReader.loadBeanDefinitions(location,)解析location,获取resources
- AbstractBeanDefinitionReader.loadBeanDefinitions(resources) 批量处理resources
- AbstractBeanDefinitionReader.loadBeanDefinitions(resource) 循环多个资源调用单个资源加载
- XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource) 读取文件流,进行加载
- XmlBeanDefinitionReader.doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 把文件流解析成Document
- XmlBeanDefinitionReader.registerBeanDefinitions,创建文档读取器
- DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(doc,XmlReaderContext) 使用默认的bean定义信息文档读取器来注册bean定义信息
- DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(element)
- DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(element,delegate)真正开始解析xml标签了
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions 解析xml文档
遍历xml文档中的节点,并进行解析
咱们这里先看普通的bean标签是如何解析成bean定义信息的,定制化在AOP时候再看是怎么执行的。
<bean id="myProperties" class="com.msgqu.debug.config.MyProperties">
<property name="url" value="${msgqu.name}"></property>
</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;
// 如果是 http://www.springframework.org/schema/beans ,那么则是默认的解析标签
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}else {
// 解析定制化标签
delegate.parseCustomElement(ele);
}
}
}
}else {
// 解析定制化标签
delegate.parseCustomElement(root);
}
}
DefaultBeanDefinitionDocumentReader.parseDefaultElement(ele, delegate) 解析默认标签
开始解析标签
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)) {
//解析bean标签
processBeanDefinition(ele, delegate);
}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
doRegisterBeanDefinitions(ele);
}
}
DefaultBeanDefinitionDocumentReader.processBeanDefinition 开始解析bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean定义信息元素,并包装成BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionParserDelegate.parseBeanDefinitionElement(ele) 使用策略解析类对bean标签进行解析
BeanDefinitionParserDelegate是bean标签的解析类
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//获取到id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// name属性是全限定类名,方便后面实例化的时候使用,也会用于判断这个对象是否是class
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//注册别名,咱们知道,一个bean对象可以有多个别名
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);
}
//检查bean的名称是必须的
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//创建beanDefinition,解析bean标签中的属性,并赋值给BeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
//这里可以扩展bean名称生成器,有兴趣的可以了解哈
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
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);
// 返回bean定义信息的包装者
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
BeanDefinitionParserDelegate.parseBeanDefinitionElement 根据bean标签创建出bean定义信息
这里创建出的bean定义信息是GenericBeanDefinition
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//包装bean名称,放置到ArrayDeque中 类似标识递归中操作的过程一样 ,方便在解析过程中获取对应标签。
this.parseState.push(new BeanEntry(beanName));
//从bean标签中获取class 和 parent 属性值
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 {
//创建bean定义信息
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析bean的其他属性 singleton、scope、abstract、lazy-init、autowire、autowire-candidate、primary、factory-method、factory-bean
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析子标签
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//方法替换
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造,为了方便实例化
parseConstructorArgElements(ele, bd);
//解析Property属性
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
//返回GenericBeanDefinition
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;
}
BeanDefinitionParserDelegate.parsePropertyElement 解析bean标签中的 标签
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
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;
}
//解析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();
}
}
BeanDefinitionParserDelegate.parsePropertyValue 解析
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element");
// Should only have one child element: ref, value, list, etc.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}else {
subElement = (Element) node;
}
}
}
//得到 ref 和 value 的值是否存在
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) {
//如果是引用类型 ,进行包装成运行时bean引用 <property name="field" ref="beanName"></property>
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) {
//创建value值包装 (value值,及类型)<property name="url" value="${com.xxx}"/>
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}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;
}
}
现在咱们已经获取到了BeanDefinition咱们再回到parseBeanDefinitionElement方法中
BeanDefinitionReaderUtils.registerBeanDefinition 注册bean的定义信息
看注册之前,咱们试想下,bean的定义信息会注册到哪里呢?
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
//注册bean定义信息 registry:DefaultListableBeanFactory
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 这里设计的还是比较巧妙,Map中 key是别名,value是beanName
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
DefaultListableBeanFactory.registerBeanDefinition 注册bean定义信息
注册之前咱们试想下,如果是自己的来存储的话,会使用什么样的数据结构?
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 existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果缓存中存在bean定义信息,那么要求是必要支持bean定义信息的覆盖
//在这属性是在咱们创建完容器的时候设置的定制化属性,想不起来可以看下
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
//把解析出的bean定义信息注册到Map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}else {
if (hasBeanCreationStarted()) {
//如果已经创建
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}else {
// 注册到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
单个bean标签也注册完了,咱们梳理下流程
bean定义信息是为了创建bean对象的时候使用,除了特殊情况(FactoryBean等),基本上都会先创建bean定义信息,所以这块是比较周要的一环
- 加载配置文件locations
- 创建xml解析器
- 解析标签,并生成bean定义信息
- 解析标签内的属性
- 注册bean定义信息