目录
使用示例(已过时):
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("bean.xml"));
UserService userService2 = (UserService) bf.getBean("xxx");
userService2.query();
分析:
- 通过XmlBeanFactory的构造方法,创建XmlBeanFactory实例
- 通过XmlBeanFactory实例的getBean()方法获取执行bean实例
- 调用目标bean的方法
XmlBeanFactory#XmlBeanFactory实现:
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
分析:
- 调用父构造函数, 在AbstractAutowireCapableBeanFactory类的构造函数中设置忽略给定接口的自动装配功能, 并调用AbstractBeanFactory类中的setParentBeanFactory()方法设置双亲IoC容器
- 加载bean, 该方法返回int类型数值表示注册bean定义的数量
1. 配置资源加载
XmlBeanDefinitionReader#loadBeanDefinitions实现:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//1.非空判断及日志记录
...
//2.通过set集合来记录当前正在加载的资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//将encodedResource添加到currentResources集合中,如果添加失败,则抛出异常
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
//3.加载bean
try {
//通过encodedResource获取已经封装的Resource对象并再次从Resource中获取其中的inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//org.xml.sax.InputSource
InputSource inputSource = new InputSource(inputStream);
//如果encodedResource中设置的编码不为空,则设置inputSource的编码
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
/**
* 加载bean,核心部分
*/
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
//关闭输入流
inputStream.close();
}
}
...
finally {
//加载完毕,将encodedResource从currentResources集合中移除
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
分析:
- 非空判断及日志记录
- 通过currentResources集合来记录当前正在加载的资源
- 对资源信息进行封装并准备加载bean
- 加载完毕,将encodedResource从currentResources集合中移除
XmlBeanDefinitionReader#doLoadBeanDefinitions实现:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
/**
* 将配置文件解析为一个Document实例,以便下面对Bean定义进行解析
*/
Document doc = doLoadDocument(inputSource, resource);
/**
* 上一个方法中当把文件装换为Document后,接下来就是对bean的提取及注册
* 注册bean定义
*/
return registerBeanDefinitions(doc, resource);
}
//异常捕获
...
}
分析:
- 将配置文件解析为一个Document实例,以便下面对Bean定义进行解析; 在解析之前会获取资源文件的验证方式(DTD或XSD)
- 对bean的提取及注册bean定义
2. 配置资源解析以及根节点的获取
XmlBeanDefinitionReader#registerBeanDefinitions实现:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//实例化BeanDefinitionDocumentReader接口
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//记录统计前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
/**
* 加载及注册bean
* {@link org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document, XmlReaderContext)}
*/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//记录本次加载的BeanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
分析:
- 创建Bean定义信息解析器 (DefaultBeanDefinitionDocumentReader)
- 加载及注册bean
- 返回本次注册Bean定义的数量
DefaultBeanDefinitionDocumentReader#registerBeanDefinitions实现:
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
/**
* 获取节点的根节点,并将root作为参数继续BeanDefinition的注册
*/
doRegisterBeanDefinitions(root);
}
分析: 获取配置文件的根节点, 开始注册Bean定义信息
3. 注册BeanDefinition
DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions实现:
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
...
//解析前处理,留给子类实现(设计模式:模板方法模式)
preProcessXml(root);
/**
* 根据Root节点进行解析
*/
parseBeanDefinitions(root, this.delegate);
//解析后处理,留给子类实现(设计模式:模板方法模式)
postProcessXml(root);
this.delegate = parent;
}
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions实现:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//如果beans是默认命名空间
if (delegate.isDefaultNamespace(root)) {
//获取beans的所有子节点,遍历,对其子节点根据是否使用默认命名空间,使用不同的解析方法
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)) {
/**
* 如果是默认命名空间(对bean的处理)
*/
parseDefaultElement(ele, delegate);
}
else {
/**
* 如果不是默认命名空间(对bean的处理)
*/
delegate.parseCustomElement(ele);
}
}
}
}
//如果beans不是默认命名空间
else {
delegate.parseCustomElement(root);
}
}
分析:
- 默认命名空间解析
- 自定义命名空间解析
3.1 默认命名空间解析
DefaultBeanDefinitionDocumentReader#parseDefaultElement实现:
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>标签进行处理
- 对<alias>标签进行处理
- 对<bean>标签进行处理(这里只分析<bean>标签的解析)
- 对<beans>标签进行处理
3.1.1 <bean>标签处理解析
_3. DefaultBeanDefinitionDocumentReader#processBeanDefinition实现:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/**
* 1.解析ele,返回BeanDefinitionHolder类型实例bdHolder,经过这个方法后,bdHolder实例已经包含我们配置文件中配置的各种属性,例如:class,name,id,alias等
*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/**
* 2.当返回的bdHolder不为空的情况下若存在默认标签的字标签下再有自定义属性,还需要再次对自定义标签进行解析
*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
/**
* 3.对bdHolder进行注册
*/
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//4.发出相应事件,通知相关的监听器,这个bean已经被加载完了
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
分析:
- 解析ele, 返回BeanDefinitionHolder类型实例bdHolder, 经过这个方法后, bdHolder实例已经包含我们配置文件中配置的各种属性, 例如:class,name,id,alias等
- 当返回的bdHolder不为空的情况下若存在默认标签的字标签下再有自定义属性,还需要再次对自定义标签进行解析
- 对bdHolder进行注册
- 发出相应事件,通知相关的监听器,这个bean已经被加载完了
_3. BeanDefinitionReaderUtils#registerBeanDefinition实现:
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
// 根据主名称注册bean定义信息
String beanName = definitionHolder.getBeanName();
/**
* GenericApplicationContext类实现了BeanDefinitionRegistry接口,
* 并且在 GenericApplicationContext类中维护了一个DefaultListableBeanFactory beanFactory (卧槽, 终于见到bean工厂了)
*
* 该步骤实际调用的是GenericApplicationContext类中的registerBeanDefinition()方法
*{@link org.springframework.context.support.GenericApplicationContext#registerBeanDefinition(String,BeanDefinition)}
*/
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果该bean有别名的话, 为bean名称注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
分析:
- 获取beanName, 注册Bean定义信息时以BeanName为键进行注册
- 注册BeanDefinition
- 注册别名(key=beanName, value=alias)
_2. GenericApplicationContext类定义信息:
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
//bean工厂, 用来注册bean定义信息
//DefaultListableBeanFactory中维护了一个
private final DefaultListableBeanFactory beanFactory;
. . . . . .
}
3.1.2 BeanDefinition的注册
GenericApplicationContext#registerBeanDefinition ==> DefaultListableBeanFactory#registerBeanDefinition实现:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
. . .
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
/**
* 注册前的最后一次校验,这里的校验不同于之前的XML文件校验
* 主要是对于AbstracBeanDefinition属性中的methodOverrides校验,
* 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法不存在
*/
((AbstractBeanDefinition) beanDefinition).validate();
}
. . .
}
//判断该beanName是否已经注册 ,根据不同的设置记性处理; (不愧是Spring, 在我模拟的SpringIOC中我管它那么多, 直接覆盖 ,简单粗暴)
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果对应的BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常
. . .
//注册beanDefinition(将beanDefinition放入map缓存中)
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//处理注册未被注册的beanName的情况
else {
/**
* 检查这个工厂的bean创建阶段是否已经开始,即 是否有任何bean被标记为同时创建。
* 如果bean工厂的bean创建已经开始, 那么就不能在beanDefinitionNames集合中添加beanName; 因为创建bean时, 会迭代beanDefinitionNames集合,获取beanName,获取BeanDefinition创建bean实例
* 一旦开始迭代, 则不允许在向该map集合中插入元素
*/
if (hasBeanCreationStarted()) {
//处于bean创建阶段
//因为beanDefinitionMap是全局变量,这里肯定会存在并发访问的情况
synchronized (this.beanDefinitionMap) {
//注册beanDefinitionv
this.beanDefinitionMap.put(beanName, beanDefinition);
//创建新的集合来更新存储已注册beanName的beanDefinitionNames集合
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//更新manualSingletonNames(存储单例bean)集合
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
//仍处于注册阶段
else {
//将beanName和bean的定义信息加入beanDefinitionMap集合
this.beanDefinitionMap.put(beanName, beanDefinition);
//bean定义名称列表,按注册顺序排列
this.beanDefinitionNames.add(beanName);
//手动注册的单例程序的名称列表,按注册顺序排列
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
//如果该bean定义已经注册,并且为单例,则进行重置
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
分析:
- 注册前的最后一次校验,这里的校验不同于之前的XML文件校验, 主要是对于AbstracBeanDefinition属性中的methodOverrides校验, 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法不存在
- 判断该beanName是否已经注册; 如果beanName已经注册过: 根据不同的设置进行处理(是否允许覆盖, 如果不允许,则抛出异常; 允许的话, 则进行注册)
- 如果beanName没有被注册过; 则开始检查这个工厂的bean创建阶段是否已经开始,即是否有任何bean被标记为同时创建。如果bean工厂的bean创建已经开始, 那么就不能在beanDefinitionNames集合中添加beanName; 因为创建bean时, 会迭代beanDefinitionNames集合, 获取beanName, 获取BeanDefinition创建bean实例; 一旦开始迭代, 则不允许在向该list集合中插入元素, 但是beanDefinitionMap集合可以, 因为beanDefinitionMap集合并没有被迭代, 而是通过beanName获取BeanDefinition信息;
- 如果该bean定义已经注册, 并且为单例, 则进行重置
3.2 自定义命名空间解析
BeanDefinitionParserDelegate#parseCustomElement实现:
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
/**spring.handler:
* http\://www.lic.com/schema/user=test.MyNameSpaceHandler
* 命名空间 NamespaceHandler
*/
/**
* 1.获取对应的命名空间
*/
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
/**
* 2.根据命名空间找到对应的NameSpaceHandler,用来解析XSD文件中的定义和组件定义
* {@link org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve(java.lang.String)}
*/
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
/**
* 3.调用自定义的NamespaceHandler进行解析
* {@link NamespaceHandlerSupport#parse(Element, ParserContext)}
*/
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
分析:
- 获取对应的命名空间
- 根据命名空间找到对应的NameSpaceHandler, 用来解析XSD文件中的定义和组件定义
- 调用自定义的NamespaceHandler进行解析
3.2.1 获取名称处理器
_2. DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) {
/**
* 获取所有已经配置的handler映射
*/
Map<String, Object> handlerMappings = getHandlerMappings();
//根据命名空间找到对应的信息
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
//已经做过解析的情况,直接从缓存读取
return (NamespaceHandler) handlerOrClassName;
}
else {
//没有做过解析,则返回的是类路径
String className = (String) handlerOrClassName;
try {
//利用反射将类路径转换为类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
...
//初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
/**
* 调用自定义的NamespaceHandler的初始化方法
* SpringMvc: {@link org.springframework.web.servlet.config.MvcNamespaceHandler#init()}
*/
namespaceHandler.init();
//将该handler记录在缓存中,以便下次调用该handler可以直接获取,不用再次转换
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
...
}
}
分析:
- 获取所有已经配置的handler映射
- 根据命名空间找到对应的信息
- 已经做过解析的情况,直接从缓存读取; 没有做过解析,则返回的是类路径,利用反射将类路径转换为类
- 调用自定义的NamespaceHandler的初始化方法; 初始化NamespaceHandler
示例: SpringMvc的名称空间解析器初始化方法:
@Override
public void init() {
/**
* 将标签名称与对应解析器关联
*
* 第一次尝试获取MvcNamespaceHandler时会调用该初始化方法进行初始化
*/
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
_3. NamespaceHandlerSupport#parse实现:
public BeanDefinition parse(Element element, ParserContext parserContext) {
/**
* 寻找解析器并进行解析操作,在自定义handler中并没有重写父类中parse()方法,因此此处是调用父类AbstractBeanDefinitionParser中的parse()方法
*
* 在parse()方法中根据标签命名空间获取不同的解析进行解析
* 例如: 标签:<context:component-scan base-package="com.ioc.lic"/>的解析为ComponentScanBeanDefinitionParser
* 该解析器会去解析包路径信息, 注册包路径下的所有BeanDefinition
*/
BeanDefinitionParser parser = findParserForElement(element, parserContext);
/**
* 解析器1:
* {@link AbstractBeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}
* 解析器2:<context:component-scan base-package="com.ioc.lic"/>
* {@link org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}
*/
return (parser != null ? parser.parse(element, parserContext) : null);
}
分析:
- 根据不同的定义标签获取对应的解析器进行解析
- 调用解析器中的parse()解析该标签 (这里以<context:component-scan base-package="com.ioc.lic"/>标签为例进行分析)
3.2.2 根据标签名称获取解析器
_1.NamespaceHandlerSupport#findParserForElement实现:
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
//获取元素名称,也就是<myname:user>中的user,若在实例中,此时localName为user
String localName = parserContext.getDelegate().getLocalName(element);
//根据user找到对应的解析器,也就是在 registerBeanDefinitionParser("user", new UserBeanDefinitionParser()) 中注册的解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
3.2.3 解析自定义标签
ComponentScanBeanDefinitionParser#parse实现:
public final BeanDefinition parse(Element element, ParserContext parserContext) {
/**
* 解析element
* {@link AbstractSingleBeanDefinitionParser#parseInternal(Element, ParserContext)}
*/
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
...
//将AbstractBeanDefinition装换成BeanDefinitionHolder并注册
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//注册
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
//需要通知监听器进行处理
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
...
}
return definition;
}
分析:
- 获取到包路径信息
- 配置扫描器, 扫描包路径, 注册BeanDefinition
ClassPathBeanDefinitionScanner#doScan实现:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
//存储扫描到的BeanDefinition信息
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
/**
* 循环遍历包路径信息,进行解析,注册
*/
for (String basePackage : basePackages) {
/**
* 扫描出该包路径下左右的候选Bean
*/
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
/**
* 对所有的候选bean进行解析
*/
for (BeanDefinition candidate : candidates) {
//获取Scope属性
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//根据Bean信息生成BeanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//对于配置类型BeanDefinition类型和注解类型BeanDefinition类型进行区分设置
if (candidate instanceof AbstractBeanDefinition) {
/**
* 如果这个类是AbstractBeanDefinition的子类
* 则为他设置默认值,比如lazy,init destory
*/
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
/**
* 检查并且处理常用的注解
* 这里的处理主要是指把常用注解的值设置到AnnotatedBeanDefinition当中
* 当前前提是这个类必须是AnnotatedBeanDefinition类型的,说白了就是加了注解的类
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//判断注册器中是否已经存在该BeanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
/**
* 注册BeanDefinition
*/
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
至此, 使用XmlBeanFactory来初始化IOC容器解析完成;
相关文章:
Spring源码解析二 (IOC容器初始化方式一:XmlBeanFactory)
Spring源码解析三 (IOC容器初始化方式二:ClassPathXmlApplicationContext)
Spring源码解析四 (IOC容器初始化方式三: AnnotationConfigApplicationContext[包路径配置方式])
Spring源码解析五 (IOC容器初始化方式四: AnnotationConfigApplicationContext[Java配置类方式])