以下说法若有不对的地方欢迎大家指正
我这里用的是断点不断跟进的方式
spring的版本为3.2.2
以下是一张方法的调用图 方便理解
最近在看spring的IoC具体实现
其实也没有什么太大的心得 就是不断进行断点调试 然后看一下过程
这个过程其实并不复杂 只是一层层不断调用有点头晕罢了
以下我来说说具体的BeanDefinition载入和注册的过程
首先我这边是以ClassPathXmlApplicationContext为IoC容器的 他底下是维护了一个DefaultListableBeanFactory
bean的注册工作其实是在DefaultListableBeanFactory中完成的
这个Map的定义和实现如下:
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
这边是主要的过程(如果我写错了 谢谢指正^_^)
1、 通过XML解析接到Document对象标准的(org.w3c.dom.Document)
2、 在documentReader中实现这个按照Spring的Bean规则进行解析的过程
3、 实际的解析工作是交给documentReader中的BeanDefinitionParserDelegate完成的
4、 BeanDefinitionParserDelegate把解析的beanDefinition交给BeanDefinitionHolder
5、 在documentReader中调用BeanDefinitionReaderUtils.registerBeanDefinition(,)向IoC容器中注册
为了直观 我把一些主要的代码放出来并写上自己的注释 以下:
// XmlBeanDefinitionsReader中的方法 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); // 标准的org.w3c.dom.Document对象 Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); // 完成标准的document到spring定义的bean规则解析的过程 return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { ... ...
// 同样是XmlBeanDefinitionsReader中的方法 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 得到一个BeanDefinitionDocumentReader的对象来按照bean规则解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); // 获取解析前的bean数目 第一次的话应该是0 int countBefore = getRegistry().getBeanDefinitionCount(); // 具体的解析过程以下完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
// 以上的documentReader.registerBeanDefinitions(,)方法调用了DefaultBeanDefinitionDocumentReader中的方法 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); // 得到根元素 Element root = doc.getDocumentElement(); // 这边开始做解析 doRegisterBeanDefinitions(root); }
// 同样是调用了DefaultBeanDefinitionDocumentReader中的方法
protected void doRegisterBeanDefinitions(Element root) {
// 这部分是关于profile的(spring 3.1之后才有的吧?) 绕过
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
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;
this.delegate = createHelper(this.readerContext, root, parent);
// 在DefaultBeanDefinitionDocumentReader中什么都不做
preProcessXml(root);
// 这边就是具体的解析了
parseBeanDefinitions(root, this.delegate);
// 在DefaultBeanDefinitionDocumentReader中什么都不做
postProcessXml(root);
// 还原
this.delegate = parent;
}
// DefaultBeanDefinitionDocumentReader中的方法 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如下 同样是DefaultBeanDefinitionDocumentReader中的方法 // 根据不同的名称执行不同的操作 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); } }
//同样是DefaultBeanDefinitionDocumentReader中的方法 这是以上的processBeanDefinition(ele, delegate) protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // bdHolder就是BeanDefinitionHolder // 解析实际都是靠BeanDefinitionParserDelegate中的方法完成的 这里面的代码太多了就不跟进了 // 需要的可以自己去看下 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 这句话就是向BeanFactory注册bean 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)); } }
// BeanDefinitionReaderUtils中的静态方法 public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); // 传入的这个registry其实就是在之前的DefaultListableBeanFactory实例 因为 // DefaultListableBeanFactory实现了BeanDefinitionRegistry接口可以注册bean registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
// DefaultListableBeanFactory中的方法 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); } } synchronized (this.beanDefinitionMap) { Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 如果存在了同名的bean if (oldBeanDefinition != null) { //如果不允许bean的覆盖的话就会抛出异常 if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } // 可以看到其实内部还是一个Map的结构来维护的 this.beanDefinitionMap.put(beanName, beanDefinition); } resetBeanDefinition(beanName); }
具体过程如上
这边只是阐述了一下这个过程 有兴趣的可以自己跟进查看更详细的解析过程
相关推荐
Spring BeanDefinition 类图结构,形象展示Spring是如何存储Bean信息的。通过类图和源码更好的理解Spring BeanDefinition存储结构
在本文中,我将讨论棘手的Spring Boot bean定义覆盖机制。 为了使您对该主题更加清楚,让我们从小测验开始。请看下一个简单的例子。 因此,我们有2种配置,它们使用名称beanName实例化bean,在主应用程序中,我们仅...
BeanDefinition基础信息讲解 BeanDefinition是Spring框架中一个非常重要的概念,它是Bean的元数据,用于描述Bean的各种信息,例如Bean的名称、类名称、Scope、依赖关系等。在Spring框架中,BeanDefinition是一个...
除此之外,BeanDefinition还包含属性值(属性与值的键值对)、构造函数参数、属性注入点(property references)和方法注入点(method injection points)等信息。这些信息通过实现BeanDefinition的子接口(如...
Spring中的BeanDefinition是核心概念,它是Spring IOC容器的基础,用于描述Bean的元数据,包括Bean的行为、依赖关系和其他配置信息。BeanDefinition包含了Bean的全限定类名、作用域、生命周期回调方法、依赖的其他...
Spring 源码学习五:BeanDefinition 装载 1 在 Spring 框架中,BeanDefinition 是一个核心概念,它描述了一个 Bean 的定义,包括其依赖项、作用域、生命周期等信息。在本篇文章中,我们将深入探讨 Spring 的源码,...
在深入Spring源码的学习过程中,我们主要关注BeanDefinition的装载过程。BeanDefinition是Spring框架的核心概念,它包含了关于Bean的所有元数据,如类名、属性、依赖关系等。在Spring初始化时,会读取XML配置文件,...
BeanDefinition就是实现这一概念的关键元素,它包含了关于一个bean的所有元信息,用于描述bean的属性、行为以及与其他bean的关系。 在BeanFactory篇中,我们了解到BeanFactory在启动时会从配置元信息(通常是XML...
Spring Bean Factory, Bean definition 结构图;processOn
二、BeanDefinition的注册与加载 在Spring容器启动时,会通过BeanDefinitionReader读取XML配置文件或通过AnnotationConfigApplicationContext读取注解配置,将BeanDefinition注册到BeanDefinitionRegistry中。注册...
#### 创建BeanDefinition 接下来,使用`BeanDefinitionBuilder`来构建Bean的定义。`BeanDefinitionBuilder`提供了简洁的API来定义一个Bean的所有属性和行为,包括它的类型、依赖注入的属性等。在这个例子中,我们...
在 Spring 中,我们可以使用 BeanDefinition 来实现动态注册 Bean。BeanDefinition 是 Spring 框架中的一种核心概念,它提供了一种灵活的方式来定义 Bean。 首先,我们需要创建一个 BeanDefinitionBuilder 对象,...
##### 1.1 BeanDefinition定义与继承体系 **BeanDefinition** 是Spring框架中一个非常重要的概念,它本质上是用来描述一个Bean(即Java对象)的配置元数据。这些元数据包含了Bean的属性值、依赖关系、生命周期回调...
在BeanDefinition中,有两个与Bean生命周期相关的属性:initMethodName和destroyMethodName。它们分别指定了Bean初始化和销毁时要调用的方法,这对于实现Bean的生命周期回调非常关键。例如,当Bean被创建后,Spring...
spring 动态注册 beanspring 动态注册 beanspring 动态注册 bean
【实验一:使用Session Bean和JDBC技术完成登录和注册功能】 实验一旨在让学生掌握Session Bean的基本功能,包括无状态(Stateless)和有状态(Stateful)Session Bean的使用,以及如何配置服务器和客户端。此外,...
首先,我们需要从 beanDefinitionMap 中通过 beanName 获得 BeanDefinition,然后从 BeanDefinition 中获得 beanClassName,最后通过反射初始化 beanClassName 的实例 instance。构造函数从 BeanDefinition 的 ...
spring的bean动态加载则需要对相应的bean进行动态注册,以及jar与class文件动态加载。测试示例中是spring boot 的部分代码,动态加载的内容为接口实现类,且初始化时加载本地的实现类,动态加载后改为非程序加载目录...
如果是,那么它们需要注册BeanDefinition。此外,Spring还会遍历配置类中的`BeanMethod`,即带有`@Bean`注解的方法,为每个方法生成对应的BeanDefinition。如果遇到方法重载,即相同类型的方法,Spring不会生成新的...
一旦创建了`BeanDefinition`,就可以将其注册到`BeanDefinitionRegistry`,通常就是Spring的`DefaultListableBeanFactory`。 以下是一个简单的示例,展示了如何实现动态扫描和注册Bean: ```java ...