spring
Spring5
XML
通过读取xml注册bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.jame.pojo.User"/>
</beans>
public static void test1(){
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
Object o = factory.getBean("user");
System.out.println(o);
}
首先看XmlBeanFactory结构
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
在创建XmlBeanFactory时传入了一个ClassPathResource对象,先来看这个对象
在java中将不同的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同的资源的读取逻辑,而URL没有提供一些基本的方法,这些都是Spring对内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源
InputStreamSource封装任何能返回InputStream的类,比如File,ClassPath下的资源等等,它只有定义一个方法:getInputStream(); 该方法返回一个新的InputStream对象
Resource接口抽象了所有的Spring内部使用到的底层资源,首先它定义了3个判断当前资源状态的方法,存在性(exists),可读性(isReadable),是否处于打开状态(isOpen),另外Resource接口还提供不同资源到URL URI File类型的转换,以及获取lastModified属性,文件名(不带路径信息的文件名,getFilename())的方法,创建基于当前路径创建相对资源的方法 createRelative()
有了Resource接口后便可以对资源文件进行统一处理
ClassPathResource
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
当通过Resource相关类完成了对配置文件进行封装后,配置文件的读取工作就交给XmlBeanDefinitionReader来处理
接下来就开始进入构造方法
XmlBeanFactory
public XmlBeanFactory(Resource resource) throws BeansException {
//调用XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)构造方法
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加载资源的切入点
this.reader.loadBeanDefinitions(resource);
}
在进行解析xml文件之前,先看一下super调用的方法
AbstractAutowireCapableBeanFactory
public AbstractAutowireCapableBeanFactory() {
super();
//忽略给定接口的自动装配功能
//默认情况下获取A,而A的Bean属性还有B,而B还没有初始化,那么Spring会将B初始化,
//但是某些情况下不会初始化B,例如B继承了BeanFactoryAware接口
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
现在可以看this.reader.loadBeanDefinitions(resource);
方法了
主要流程如下
- 封装资源文件 进入XmlBeanDefinitionReader后先对参数Resource使用EncodedResource类进行封装
- 获取输入流,从Resource中获取对应的InputStream并构造InputSource
- 通过构造的InputSource实例和Resource实例继续调用函数doLoadBeanDefinitions
XmlBeanDefinitionReader
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
EncodedResource的作用是对资源文件的编码进行处理,主要逻辑体现在getReader()方法中,当设置了编码Spring就会使用相应的编码作为输入的编码
EncodedResource
public Reader getReader() throws IOException {
if (this.charset != null) {
return new InputStreamReader(this.resource.getInputStream(), this.charset);
}
else if (this.encoding != null) {
return new InputStreamReader(this.resource.getInputStream(), this.encoding);
}
else {
return new InputStreamReader(this.resource.getInputStream());
}
}
当构造好encodedResource对象后,再次传入了loadBeanDefinitions(new EncodedResource(resource))
这个方法内部才是真正的数据准备阶段
XmlBeanDefinitionReader
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//通过属性来记录已经加载的资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//从encodedResource中获取Resource对象,然后再从Resource中获取InputStream对象
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//这个类并不来自Spring,全路径为org.xml.sax
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//真正核心部分=======================----
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
//=========================================
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//通过inputSource获取Document对象
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
//剩下全部都是异常处理
上面的代码其实就做了3件事
- 获取对XML文件的验证模式
- 加载XML,并得到对应的Document
- 根据返回的Document注册Bean信息
首先来看第一件事:获取xml文件验证模式
简单说下DTD和XSD区别
DTD是一种xml约束模式语言,一个DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用规则,可使用的实体或符号规则
要是用DTD验证模式只需要在XML文件头部声明即可
XML Schema 语言就是XSD 它描述了xml文档的结构,可以指定一个xml schema来验证某个xml,xml schema本身就是一个xml文档,可以用通用xml解析器解析它
在使用xml schema文档对xml实例文档进行检验,除了要声明名称空间外,还必须指定该名称空间所对应的xml schema文档储存位置,通过schemaLocation属性来指定xml schema文件位置或URL地址
验证模式的读取
XmlBeanDefinitionReader
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
//如果手动指定验证模式则使用指定的验证模式
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);
//如果未指定则使用自动检测
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
return VALIDATION_XSD;
}
detectValidationMode(resource);自动检测验证的模式
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
InputStream inputStream;
try {
inputStream = resource.getInputStream();
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
"Did you attempt to load directly from a SAX InputSource without specifying the " +
"validationMode on your XmlBeanDefinitionReader instance?", ex);
}
try {
//又交给detectValidationMode去完成验证
return this.validationModeDetector.detectValidationMode(inputStream);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
resource + "]: an error occurred whilst reading from the InputStream.", ex);
}
}
XmlValidationModeDetector
//判断方法就是是否包含DOCTYPE,如果包含就是DTD,否则就是XSD
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
//如果读取的是空行或者是注释略过
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
//如果读到<开始符号,验证模式一定会在开始符号之前
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}
获取Document
通过验证就可以进行Document加载了,同样在XmlBeanFactoryReader类中没有实现,而是调用了loadDocument方法来实现
DocumentLoader I
Document loadDocument(
InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
throws Exception;
这是个接口,他的实现类为
DefaultDocumentLoader
//通过SAX解析XML文档
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
//创建DocumentBuilderFactory对象
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
//创建DocumentBuilder对象
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
//解析inputSource来获取Document对象
return builder.parse(inputSource);
}
主要来看一下doLoadDocument方法传入的 getEntityResolver()参数
XmlBeanDefinitionReader
protected EntityResolver getEntityResolver() {
if (this.entityResolver == null) {
// Determine default EntityResolver to use.
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
EntityResoulver用法
如果SAX应用程序需要实现自定义处理外部实体,必须要实现此接口并使用setEntutyResolver方法向SAX驱动器注册一个实例,–对于解析一个XML,SAX首先读取该XML文档上的声明,根据声明去寻找对于的DTD定义,以便对文档进行验证,默认是从网络上下载对应的DTD声明,而EntityResolver的作用就是项目本身就可以提供一个DTD文件声明的方法,由程序来寻找DTD声明的过程,比如讲DTD文件放到项目的某处,在实现时直接将此文档读取返回给SAX即可,不用通过网络来寻找相应的声明
EntityResolver的接口方法声明
EntityResolver I
public abstract InputSource resolveEntity (String publicId,String systemId)
如果解析验证模式为XSD的配置文件会读取到两个参数
publicId : null
systemId : xxxxxxxxxxx
而解析验证模式为DTD的配置文件
publicId : xxx
systemId : xxx
根据之前Spring通过getEntityResilver()方法对EntityResolver的获取,Spring中使用DelegatingEntityResolver类为EntityResolver的实现类,resolverEntity的实现方法如下
DelegatingEntityResolver
public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)
throws SAXException, IOException {
if (systemId != null) {
if (systemId.endsWith(DTD_SUFFIX)) {
//如果是dtd从这里解析
return this.dtdResolver.resolveEntity(publicId, systemId);
}
else if (systemId.endsWith(XSD_SUFFIX)) {
//通过META-INF/Spring.schemas解析
return this.schemaResolver.resolveEntity(publicId, systemId);
}
}
// Fall back to the parser's default behavior.
return null;
}
直接截取后缀来判断是那种解析类型
如果是DTD,会去当前路径下寻找,如果是XSD,默认是到META-INF/Spring.schemas文件中找到对应systemid的XSD文件并加载
BeansDtdResolver
public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Trying to resolve XML entity with public ID [" + publicId +
"] and system ID [" + systemId + "]");
}
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf('/');
int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
if (dtdNameStart != -1) {
String dtdFile = DTD_NAME + DTD_EXTENSION;
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isTraceEnabled()) {
logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (FileNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
}
}
}
}
// Fall back to the parser's default behavior.
return null;
}
解析和注册BeanDefinitions
XmlBeanDefinitionReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//使用DefaultBeanDefinitionDocument实例化BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//记录统计前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//记录本次加载的BeanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
进入registerBeanDefinitions方法
DefaultBeanDefinitionDocumentReader
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
//提取DocumentElement
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//处理profile属性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//处理前解析,留给子类实现
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//处理后解析,留给子类实现
postProcessXml(root);
this.delegate = parent;
}
首先程序会回去beans节点是否定义了profile属性,如果定义了则会需要到环境变量中去寻找,所以这里首先断言environment不可能为空,因为profile是可以同时指定多个的,需要程序对其拆分,并解析每个profile是都符合环境变量中所定义的,不定义则不会浪费性能去解析。
解析并注册BeanDefinition
DefaultBeanDefinitionDocumentReader
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//对bean的处理
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 {
//对bean的处理
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
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);
}
}
先从bean标签开始
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
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);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
(1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后, bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class, name,id, alias之类的属性。
(2)当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。
(3)解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。
(4)最后发出响应事件,通知想关的监听器,这个bean已经加载完成了。
BeanDefinitionParserDelegate
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
//解析name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割name属性
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");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//进一步解析
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
//如果不存在beanname 那么根据spring命名规则生成对应的beanname
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;
}
(1)提取元素中的id以及name属性。
(2)进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中。
(3)如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName
(4)将获取到的信息封装到BeanDefinitionHolder的实例中。
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//解析Class属性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
//解析parent属性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//创建用于承载AbstractBeanDefinition类型的GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析默认的bean的各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据
parseMetaElements(ele, bd);
//解析lookup-method 属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数
parseConstructorArgElements(ele, bd);
//解析property子元素
parsePropertyElements(ele, bd);
//解析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);
}
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;
}
创建用于属性承载的BeanDefinitionBeanDefinition是一个接口,在Spring中存在三种实现: RootBeanDefinition,ChildBeanDefinition以及GenericBeanDefinition。三种实现均继承了AbstractBeanDefiniton ,其中BeanDefinition是配置文件元素标签在容器中的内部表示形式。元素标签拥有class, scope, lazy-init等配置属性, BeanDefinition则提供了相应的beanClass, scope, lazylnit属性, BeanDefinition和中的属性是一一对应的。其中RootBeanDefinition是最常用的实现类,它对应一般性的元素标签, GenericBeanDefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务类。在配置文件中可以定义父和子,父用RootBeanDefinition表示,而子用ChildBeanDefiniton表示,而没有父的就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象Spring通过BeanDefinition将配置文件中的配置信息转换为容器的内部表示,并将这些BeanDefiniton注册到BeanDefinitonRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息。
BeanDefinitionParserDelegate
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
//=====================
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
//parentName可能为空
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
//如果classLoader不为空,则传入使用的classLoader同一虚拟机加载类对象,否则只是记录classname
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
当我们创建了bean信息的承载实例后,便可以进行bean信息的各种属性解析了,parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);