上次分享中,提到了 Spring 把查找出来的资源加载解析成为 Document 对象,供后面的 BeanDefinition 注册使用。本次分享,就来看看 BeanDefinition 是如何注册的,以及他注册到什么地方。
1. 分析源码了解 BeanDefinition 的注册过程
1.1org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 创建 BeanDefinitionDocumentReader,默认创建是 DefaultBeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); // resource 其实就是 ApplicationContext 实例 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } // 你可以通过配置 documentReaderClass 属性来改变 BeanDefinitionDocumentReader 的实例 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } // 创建 XmlReaderContext 传递到 documentReader 上 protected XmlReaderContext createReaderContext(Resource resource) { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } // resouce 等信息设置到上下文中 return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.namespaceHandlerResolver); }
通过上面的方法,初始准备了解析 Bean 定义需要的解析环境,把相关的解析需用的参数设置完成。其中有很重要的命名空间处理器(NamespaceHandlerResolver)会在后续的分享中讲解。
1.2 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
doRegisterBeanDefinitions方法是被registerBeanDefinitions调用的,完成注册工作转交给BeanDefinitionParserDelegate 的工作。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { // 设置上下文 this.readerContext = readerContext; logger.debug("Loading bean definitions"); // 获取 Document 根元素 Element root = doc.getDocumentElement(); // 执行注册操作 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); // 解析 profile 属性,判断是否需要注册此资源文件(spring3.0的新属性) if (StringUtils.hasText(profileSpec)) { Assert.state(this.environment != null, "environment property must not be null"); String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!this.environment.acceptsProfiles(specifiedProfiles)) { return; } } // 创建 BeanDefinitionParserDelegate,真正做解析工作的类实例 // any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; // 在实例化的同时,需要检查 Bean 上面的初始化配置是否正确 // BeanDefinitionParserDelegate#initDefaultsElement, BeanDefinitionParserDelegate) this.delegate = createHelper(readerContext, root, parent); preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
1.3 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
// 解析 Bean 定义的根节点,包含 import, alias, bean。 // Root 是解析的DOM根节点 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 如果root 节点的namespace是空,或者是 http://www.springframework.org/schema/beans 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; // 和root节点的判断方式相同,如果是默认命名空间 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } // 非默认命名空间,自定义节点 else { 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); } }
深入看看里面的具体实现,如果不关心这个里面的细节可以选择跳过。
/** * import 元素解析,根据配置的 resource 属性,再一次从资源查找入手,进行导入 bean 定义解析 * Parse an "import" element and load the bean definitions * from the given resource into the bean factory. */ protected void importBeanDefinitionResource(Element ele) { // 获取 resource 属性 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // Resolve system properties: e.g. "${user.dir}" // 处理系统属性 location = environment.resolveRequiredPlaceholders(location); // 记录真实的资源(用表达式配置的资源可能出现多个) Set<Resource> actualResources = new LinkedHashSet<Resource>(4); // 判断是否是绝对路径 // Discover whether the location is an absolute or relative URI boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" } // Absolute or relative? // 如果是绝对路径,直接解析对应绝对路径的 Bean 定义资源就可以了 if (absoluteLocation) { try { // 这个方法在前面资源装载中已经分享过, AbstractBeanDefinitionReader#loadBeanDefinitions(String, Set<Resource>) int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } // 相对路径 else { // No URL -> considering resource location as relative to the current file. try { int importCount; // 如果资源支持创建相对路径,则创建。 Resource relativeResource = getReaderContext().getResource().createRelative(location); // 判断如果资源存在,进行解析 if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } // 如果不存在,在拼一下绝对路径,进行解析。如果此时无法查找到资源,就会抛异常了 else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); // 通知 import 元素已经解析完毕 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); } /** * 处理别名,或者说叫注册别名 * Process the given alias element, registering the alias with the registry. */ 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 { // 注册到别名Map中,后面会再次提到此处的使用 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)); } } /** * 处理 bean 元素,本身不处理,交给了 BeanDefinitionParserDelegate * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析Bean定义,存放在 BeanDefinitionHolder 中 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 判断是否需要装饰 BeanDefinition,如果需要装饰,返回装饰后的 Bean 定义 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 注册 Bean 到 Factory 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)); } }
BeanDefinitionHolder
BeanDefinitionHolder 不仅包含了 BeanDefinition 信息,同时记录了对应的Bean的名称以及别名信息。
1.4 org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element, BeanDefinition)
BeanDefinitionParserDelegate解析 Bean 定义的地方。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // id 属性 String id = ele.getAttribute(ID_ATTRIBUTE); // name 属性,可以用“,;”分割,得到别名定义 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // bean 的唯一名称是定义的 id 属性,不是name // 如果当没有定义 id 属性时,从定义的别名中取得一个 String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } // 如果不是嵌套bean,验证 beanName 唯一性 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 解析 bean 属性值以及子元素标签 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { // 如果是内部 bean,创建内部 bean 名称 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.isDebugEnabled()) { logger.debug("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); // 返回 BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
相关推荐
总结来说,BeanDefinition是Spring IoC容器的核心组成部分,它封装了bean的所有配置信息,使容器能够根据这些信息实例化、配置、管理bean,从而实现了控制反转。通过XML配置文件,我们可以轻松地定义bean及其属性,...
1. **读取配置**:Spring容器读取XML、Java配置或基于注解的配置信息,构建BeanDefinition对象,其中包含了对象的类名、属性、依赖等信息。 2. **Bean实例化**:根据BeanDefinition,Spring容器创建Bean实例,可以是...
1. `BeanDefinition`:每个 Bean 在容器中都有一个对应的 `BeanDefinition`,它存储了 Bean 的所有元数据,如类名、初始化方法、依赖等。 2. `BeanFactory`:这是最基础的 Bean 容器接口,负责创建和管理 Bean。 3. ...
- 在Spring的XML配置中,定义的每一个`<bean>`标签都会被解析成一个`BeanDefinition`对象。 - `BeanDefinition` 对象包含了一系列属性,这些属性来自`<bean>`标签的属性配置,例如 `class` 属性与 `...
IoC 容器中存放的是 Bean 的定义即 BeanDefinition,BeanDefinition 接口中包含了这个类的 Class 信息以及是否是单例等。那么如何从 BeanDefinition 中实例化出 Bean 对象呢? BeanFactory 中 getBean 的主体思路是...
通过设置资源解析器和环境、设置配置路径、初始化 BeanFactory、加载 Bean 定义资源、解析 Bean 定义资源和注册 BeanDefinition,这些步骤组成了 IOC 初始化流程。 在 Spring 框架中,IOC 容器是核心组件,负责管理...
- **Groovy Bean Definition DSL**:Spring 4.0引入了Groovy DSL来定义Bean配置,提供了一种更简洁、更易于阅读的方式。 - **核心容器改进**:包括BeanFactory后处理器的增强、更强大的Bean工厂功能等。 - **Web改进...
Spring中的BeanDefinition是核心概念,它是Spring IOC容器的基础,用于描述Bean的元数据,包括Bean的行为、依赖关系和其他配置信息。BeanDefinition包含了Bean的全限定类名、作用域、生命周期回调方法、依赖的其他...
- **BeanDefinitionDocumentReader**:读取XML文档中的Bean定义,并将其解析为BeanDefinition对象。 - **ResourceEntityResolver**:用于解析资源实体。 - **ResourceLoader**:负责加载各种类型的资源。 - **...
- `registerBeanDefinition(String beanId, BeanDefinition beanDefinition)`: 注册一个Bean定义。 - `getBean(String beanId)`: 根据beanId获取Bean实例。 - `initializeBean(String beanId)`: 初始化Bean,包括...
Spring的IOC体系主要由BeanFactory和BeanDefinition组成。BeanFactory是Spring容器的基础接口,负责管理和实例化Bean。BeanDefinition则存储了Bean的元数据,如类名、属性、依赖等信息。 三、IoC容器的初始化 1. `...
`spring-5.2.3.RELEASE-schema.zip`包含了Spring的XML配置文件的XSD(XML Schema Definition)定义。这些定义文件规定了我们在Spring XML配置文件中可以使用的元素和属性,帮助我们编写符合规范的配置。通过查看这些...
在"org"这个文件夹中,可能包含了实现这些功能的类,如BeanDefinition用于存储bean的定义信息,BeanFactory作为bean的工厂,AutowiredAnnotationBeanPostProcessor处理自动注入的注解,以及可能的容器接口实现类等。...
`BeanDefinition`则存储了Bean的配置信息。 **源码分析** 对于学习和理解Spring框架,查看源码是很有帮助的。你可以深入研究这些jar包中的类和方法,了解Spring如何管理Bean,如何解析配置,以及如何执行依赖注入等...
BeanDefinition是Spring中用于描述Bean实例的关键数据结构,包含了Bean的属性、依赖对象、构造器参数等信息。而ApplicationContext则是一种更高级的容器,除了提供BeanFactory的基本功能外,还增加了许多面向框架的...
同时,对于`BeanDefinition`、`BeanPostProcessor`等关键接口的注释,能帮助我们深入理解bean的生命周期。 **源码解析**: 源码解析部分通常会详细解释Spring的各个组件和模块是如何协同工作的。例如,解析`...
我们可以通过`BeanDefinition`类来表示这些信息。当容器启动时,会根据定义创建bean实例。 1.3 依赖注入(Dependency Injection,DI) DI是IOC的一种实现方式,通过容器将依赖关系注入到对象中,而不是由对象自行...
BeanRegistry是另一个关键组件,它允许手动向IoC容器注册BeanDefinition对象。BeanDefinition包含了Bean的所有元数据,如类名、依赖关系、初始化方法等。注册过程是IoC容器填充Bean实例的前提。 在更高级别的设计中...
- **BeanDefinition的生成与注册**:Spring容器在启动时会解析这些声明,生成对应的BeanDefinition对象。BeanDefinition包含了Bean的类信息、属性、依赖关系等元数据。所有BeanDefinition会被保存在一个内部Map中,...
5. **BeanDefinition注册**:配置类被解析并注册为BeanDefinition,这样容器就知道了需要管理哪些Bean。 6. **容器刷新**:最后,调用`refresh()`方法,执行一系列初始化操作,包括调用`...