这篇文章总结得更好,不妨看看:https://www.cnblogs.com/PerkinsZhu/p/6500837.html
Spring综述
Spring是一个开源的轻量级JavaSE(Java标准版本)/JavaEE(Java企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。应用程序是由一组相互协作的对象组成。而在传统应用程序开发中,一个完整的应用是由一组相互协作的对象组成。所以开发一个应用除了要开发业务逻辑之外,最多的是关注如何使这些对象协作来完成所需功能,而且要低耦合、高内聚。业务逻辑开发是不可避免的,那如果有个框架出来帮我们来创建对象及管理这些对象之间的依赖关系。可能有人说了,比如“抽象工厂、工厂方法设计模式”不也可以帮我们创建对象,“生成器模式”帮我们处理对象间的依赖关系,不也能完成这些功能吗?可是这些又需要我们创建另一些工厂类、生成器类,我们又要而外管理这些类,增加了我们的负担,如果能有种通过配置方式来创建对象,管理对象之间依赖关系,我们不需要通过工厂和生成器来创建及管理对象之间的依赖关系,这样我们是不是减少了许多工作,加速了开发,能节省出很多时间来干其他事。Spring框架刚出来时主要就是来完成这个功能。Spring框架除了帮我们管理对象及其依赖关系,还提供像通用日志记录、性能统计、安全控制、异常处理等面向切面的能力,还能帮我管理最头疼的数据库事务,本身提供了一套简单的JDBC访问实现,提供与第三方数据访问框架集成(如Hibernate、JPA),与各种JavaEE技术整合(如JavaMail、任务调度等等),提供一套自己的web层框架SpringMVC、而且还能非常简单的与第三方Web框架集成。从这里我们可以认为Spring是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力,从而使我们可以更自由的选择到底使用什么技术进行开发。而且不管是JAVASE(C/S架构)应用程序还是JAVAEE(B/S架构)应用程序都可以使用这个平台进行开发。
而Spring则立志于全方面的简化Java开发。对此,她主要采取了4个关键策略:
1,基于POJO的轻量级和最小侵入性编程;
2,通过依赖注入和面向接口松耦合;
3,基于切面和惯性进行声明式编程;
4,通过切面和模板减少样板式代码;
而他主要是通过:面向Bean、依赖注入以及面向切面这三种方式来达成的。即IOC、AOP和DI。
Spring核心容器:由spring-beans、spring-core、spring-context和spring-expression(SpringExpressionLanguage,SpEL)4个模块组成。
spring-beans和spring-core模块是Spring框架的核心模块,包含了控制反转(InversionofControl,IOC)和依赖注入(DependencyInjection,DI)。BeanFactory接口是Spring框架中的核心接口,它是工厂模式的具体实现。BeanFactory使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。但BeanFactory容器实例化后并不会自动实例化Bean,只有当Bean被使用时BeanFactory容器才会对该Bean进行实例化与依赖关系的装配。
spring-context模块构架于核心模块之上,他扩展了BeanFactory,为她添加了Bean生命周期控制、框架事件体系以及资源加载透明化等功能。此外该模块还提供了许多企业级支持,如邮件访问、远程访问、任务调度等,ApplicationContext是该模块的核心接口,她是BeanFactory的超类,与BeanFactory不同,ApplicationContext容器实例化后会自动对所有的单实例Bean进行实例化与依赖关系的装配,使之处于待用状态。
spring-expression模块是统一表达式语言(EL)的扩展模块,可以查询、管理运行中的对象,同时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统EL,但提供了额外的功能,最出色的要数函数调用和简单字符串的模板函数。这种语言的特性是基于Spring产品的需求而设计,他可以非常方便地同SpringIOC进行交互。
2.AOP和设备支持:由spring-aop、spring-aspects和spring-instrument3个模块组成。
spring-aop是Spring的另一个核心模块,是AOP主要的实现模块。作为继OOP后,对程序员影响最大的编程思想之一,AOP极大地开拓了人们对于编程的思路。在Spring中,他是以JVM的动态代理技术为基础,然后设计出了一系列的AOP横切实现,比如前置通知、返回通知、异常通知等,同时,Pointcut接口来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关方法根据需求进行切入。
spring-aspects模块集成自AspectJ框架,主要是为SpringAOP提供多种AOP实现方法。
spring-instrument模块是基于JAVASE中的"java.lang.instrument"进行设计的,应该算是AOP的一个支援模块,主要作用是在JVM启用时,生成一个代理类,程序员通过代理类在运行时修改类的字节,从而改变一个类的功能,实现AOP的功能。在分类里,我把他分在了AOP模块下,在Spring官方文档里对这个地方也有点含糊不清,这里是纯个人观点。
3.数据访问及集成:由spring-jdbc、spring-tx、spring-orm、spring-jms和spring-oxm5个模块组成。
spring-jdbc模块是Spring提供的JDBC抽象框架的主要实现模块,用于简化SpringJDBC。主要是提供JDBC模板方式、关系数据库对象化方式、SimpleJdbc方式、事务管理来简化JDBC编程,主要实现类是JdbcTemplate、SimpleJdbcTemplate以及NamedParameterJdbcTemplate。
spring-tx模块是SpringJDBC事务控制实现模块。使用Spring框架,它对事务做了很好的封装,通过它的AOP配置,可以灵活的配置在任何一层;但是在很多的需求和应用,直接使用JDBC事务控制还是有其优势的。其实,事务是以业务逻辑为基础的;一个完整的业务应该对应业务层里的一个方法;如果业务操作失败,则整个事务回滚;所以,事务控制是绝对应该放在业务层的;但是,持久层的设计则应该遵循一个很重要的原则:保证操作的原子性,即持久层里的每个方法都应该是不可以分割的。所以,在使用SpringJDBC事务控制时,应该注意其特殊性。
spring-orm模块是ORM框架支持模块,主要集成Hibernate,JavaPersistenceAPI(JPA)和JavaDataObjects(JDO)用于资源管理、数据访问对象(DAO)的实现和事务策略。
spring-jms模块(JavaMessagingService)能够发送和接受信息,自SpringFramework4.1以后,他还提供了对spring-messaging模块的支撑。
spring-oxm模块主要提供一个抽象层以支撑OXM(OXM是Object-to-XML-Mapping的缩写,它是一个O/M-mapper,将java对象映射成XML数据,或者将XML数据映射成java对象),例如:JAXB,Castor,XMLBeans,JiBX和XStream等。
4.Web:由spring-web、spring-webmvc、spring-websocket和spring-webflux4个模块组成。
spring-web模块为Spring提供了最基础Web支持,主要建立于核心容器之上,通过Servlet或者Listeners来初始化IOC容器,也包含一些与Web相关的支持。
spring-webmvc模块众所周知是一个的Web-Servlet模块,实现了SpringMVC(model-view-Controller)的Web应用。
spring-websocket模块主要是与Web前端的全双工通讯的协议。(资料缺乏,这是个人理解)
spring-webflux是一个新的非堵塞函数式ReactiveWeb框架,可以用来建立异步的,非阻塞,事件驱动的服务,并且扩展性非常好。
5.报文发送:即spring-messaging模块。
spring-messaging是从Spring4开始新加入的一个模块,主要职责是为Spring框架集成一些基础的报文传送应用。
6.Test:即spring-test模块。
spring-test模块主要为测试提供支持的,毕竟在不需要发布(程序)到你的应用服务器或者连接到其他企业设施的情况下能够执行一些集成测试或者其他测试对于任何企业都是非常重要的。
3.7、Spirng各模块之间的依赖关系
该图是Spring5的包结构,可以从中清楚看出Spring各个模块之间的依赖关系。
什么是IOC容器
IOC(InversionofControl)控制反转:所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
DI(DependencyInjection)依赖注入:就是指对象是被动接受依赖类而不是自己主动去找,换句话说就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。
先从我们自己设计这样一个视角来考虑:
对象和对象关系怎么表示?
可能是classpath,filesystem,或者是URL网络资源,servletContext等。
IOC的具体实现
Spring框架是面向Bean编程(JavaBean指的是符合特殊要求的java类,即属性都为私有,并且有获取属性的公开get方法)在这个基础上,Spring主要通过使用工厂模式来生产Bean的实例,默认生产的Bean都是单例的,然后封装到IOC容器中(ConcurrentHashMap),以下是Spring构建中关键的九个类:
BeanFactory:bean的管理工厂,所有的bean都在该对象中进行创建、存储和销毁。
DefaultListableBeanFactory:beanFactory具体实现类
Resource:spring的配置信息,该信息可能来源于xml文件,可能来源于网络,也可能来源于数据流中。不管他从哪里来的,都封装为Resource对象。
BeanDefinition:bean的所有信息在该对象中进行封装,包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息
BeanDefinitionReader:见名知意,构建BeanDefinition的reader,也就是通过该Reader从Resource中读取信息封装为BeanDefinition。
ApplicationContext:俗称“上下文”和“控制反转”一样晦涩难懂,据我猜测之所以这样命名,是因为context继承了太多的接口,具有各种各样的功能,可以称为万能的上帝。并且所有的需要用到的bean都可以在其中取到,起到沟通上下的桥梁的作用,所以叫做“上下文”。这里可以看出其特性是:实现了各种功能接口,封装了各种bean对象。
Environment:运行环境配置信息,也就是一些配置属性,来源于:properties文件,JVM properties,system环境变量,JNDI, servlet context parameters上下文参数,专门的Properties对象,Maps等等
Document:从xml文件文件中抽取出来的本文对象。
Element:从Document中取出的node节点
所以在读源码的时候从Factory入手:
那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在Spring内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如ListableBeanFactory接口表示这些Bean是可列表的,而HierarchicalBeanFactory表示的是这些Bean是有继承关系的,也就是每个Bean有可能有父Bean。AutowireCapableBeanFactory接口定义Bean的自动装配规则。这四个接口共同定义了Bean的集合、Bean之间的关系、以及Bean行为。最基本的接口BeanFactory:
而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,Spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的IOC容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述),如果说XmlBeanFactory是容器中的屌丝,ApplicationContext应该算容器中的高帅富.
ApplicationContext是Spring提供的一个高级的IOC容器,它除了能够提供IOC容器的基本功能外,还为用户提供了以下的附加服务。
从ApplicationContext接口的实现,我们看出其特点:
1.支持信息源,可以实现国际化。(实现MessageSource接口)
2.访问资源。(实现ResourcePatternResolver接口,后面章节会讲到)
3.支持应用事件。(实现ApplicationEventPublisher接口)
web容器启动的时候,首先会生成context对象(上下文)来提供程序运行环境。根据是classpath,filesystem,或者是URL网络资源,servletContext来寻找源码入口。如果定义的是classpath配置,那么在ClassPathXmlApplicationContext类中可以看到:
由继承关系可以知道,ClassPathXmlApplicationContext继承了ResourceLoader类,所以具有加载资源的能力。在super(parent)中传入context对象,在父类中设置好资源加载器以及程序环境Environment:
在setConfigLocation()方法中定位资源:
在refresh()方法中初始化容器:
//容器初始化的过程,读入Bean定义资源,并解析注册
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//为BeanFactory配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//为BeanFactory注册BeanPost事件处理器.
//BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化信息源,和国际化相关.
initMessageSource();
// Initialize event multicaster for this context.
//初始化容器事件传播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//调用子类的某些特殊Bean初始化方法
onRefresh();
// Check for listener beans and register them.
//为事件传播器注册事件监听器.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化所有剩余的单例Bean.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
//销毁以创建的单态Bean
destroyBeans();
// Reset 'active' flag.
//取消refresh操作,重置容器的同步标识.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
最终完成IOC容器的初始化,获得BeanFactory,其本身就是容器,使用ConcurrntHashMap保存了BeanDefinition:
使用BeanDefinitionReader读取BeanDefinition,其中记录了Bean的信息(包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息),完成Bean的注册:
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
counter += loadBeanDefinitions(resource);
}
return counter;
}
//重载方法,调用下面的loadBeanDefinitions(String, Set<Resource>);方法
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
/**
* Load bean definitions from the specified resource location.
* <p>The location can also be a location pattern, provided that the
* ResourceLoader of this bean definition reader is a ResourcePatternResolver.
* @param location the resource location, to be loaded with the ResourceLoader
* (or ResourcePatternResolver) of this bean definition reader
* @param actualResources a Set to be filled with the actual Resource objects
* that have been resolved during the loading process. May be {@code null}
* to indicate that the caller is not interested in those Resource objects.
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #getResourceLoader()
* @see #loadBeanDefinitions(org.springframework.core.io.Resource)
* @see #loadBeanDefinitions(org.springframework.core.io.Resource[])
*/
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取在IoC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
//加载多个指定位置的Bean定义资源文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
//将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
//加载单个指定位置的Bean定义资源文件
Resource resource = resourceLoader.getResource(location);
//委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
//重载方法,调用loadBeanDefinitions(String)
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
//这里是载入XML形式Bean定义资源文件方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//将资源文件转为InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//从InputStream中得到XML的解析源
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里是具体的读取过程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
//关闭从Resource中得到的IO流
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();
}
}
}
实际实现方法doLoadBeanDefinitions加载BeanDefinition(关键方法两步:取得Document;注册BeanDefinition,Spring是使用SAX/DOM4J进行xml解析的):
进入关键方法doRegisterBeanDefinitions():
protected void doRegisterBeanDefinitions(Element root) {
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;
}
}
// 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实现,
//BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
//在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
preProcessXml(root);
//从Document的根元素开始进行Bean定义的Document对象
parseBeanDefinitions(root, this.delegate);
//在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
postProcessXml(root);
this.delegate = parent;
}
进行Bean解析:
//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//Bean定义的Document对象使用了Spring默认的XML命名空间
if (delegate.isDefaultNamespace(root)) {
//获取Bean定义的Document对象根元素的所有子节点
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//获得Document节点是XML元素节点
if (node instanceof Element) {
Element ele = (Element) node;
//Bean定义的Document的元素节点使用的是Spring默认的XML命名空间
if (delegate.isDefaultNamespace(ele)) {
//使用Spring的Bean规则解析元素节点
parseDefaultElement(ele, delegate);
}
else {
//没有使用Spring默认的XML命名空间,则使用用户自定义的解
//析规则解析元素节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
//Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的
//解析规则解析Document根节点
delegate.parseCustomElement(root);
}
}
//使用Spring的Bean规则解析Document元素节点
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>元素,
//按照Spring的Bean规则解析元素
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
进入processBeanDefinition():
//向IoC容器注册解析的BeanDefinito
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");
//校验解析的BeanDefiniton
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);
//检查是否有同名的BeanDefinition已经在IOC容器中注册,如果已经注册,
//并且不允许覆盖已注册的Bean,则抛出注册失败异常
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {//IOC容器中没有已经注册同名的Bean,按正常注册流程注册
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//重置所有已经注册过的BeanDefinition的缓存
resetBeanDefinition(beanName);
}
至此,context创建完成。