ApplicationContext源码及其IOC容器初始化过程的简单介绍
xsobi 2024-11-24 23:35 2 浏览
原文链接:https://www.tuicool.com/articles/MbURNnv
回顾一下IOC容器
IOC容器,就是为用户创建、管理、获取它们的实例的容器,让用户在需要使用类对象的时候,只需要向IOC容器的时候就可以了,能够实现与具体的解耦合,为其他的高级功能和特性提供基础。
IOC容器在使用之前,需要完成以下工作:
使用Spring的三种方式
1. XML 配置的方式
<? xml version= "1.0" encoding= "UTF-8" ?>
< beans >
< bean id = "girl" class = "di.MagicGirl"
init-method = "start" destroy-method = "end" >
< constructor- arg type = "java.lang.String" value = "girl" > </ constructor-arg >
< property name = "friend" ref = "
</豆>
< bean id = "boy" class = "di.Lad" >
< constructor-arg type = "java.lang.String" value = "boy" > </ constructor-arg >
< constructor-arg type = "di.MagicGirl " value = "girl" > </ constructor-arg >
</ bean >
</ beans >
复制代码
通过XML的方式来指定扫描包的范围:
< context :component-scan base - package = "demo.beans" />
复制代码
通过ApplicationContext来使用:
ApplicationContext context = new ClassPathXmlApplicationContext( "application.xml" );
复制代码
- 注解配置的方式
@Component(initMethodName = "init" , destroyMethodName = "destroy" )
公共 类 Lad 实现 Boy {
@Autowired
私人女朋友;
public Lad(String name) {
this .name = name;
}
@Autowired
public Lad( @Value( "tony" ) String name, @Qualifier( "flower" ) Girl gf) {
this .name = name;
这个.friend = gf;
系统。out .println( "调用了含有Girl 参数的构造方法" );
}
}
复制代码
通过注解的方式指定扫描包的范围:
@Configuration
@ComponentScan (basePackages = "demo.beans" )
公共类 AppConfig {
}
复制代码
或者使用下面代码的方式:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application .class );
上下文.scan ( "demo.beans" );
上下文.refresh ();
复制代码
- JavaBean 配置的方式
@Configuration
@ComponentScan (basePackages = "demo.beans" )
公共类 AppConfig {
@豆角,扁豆
公共小伙子小伙子(){
返回 新的 小伙子(“”);
}
}
复制代码
通过上面简单的介绍,可以知道,当要使用Spring的时候,只需要使用Spring提供的ApplicationContext的API,而ApplicationContext就是IOC容器
ApplicationContext的继承体系
首先在看源码之前需要明确的应用上下文是什么,才能做些什么,怎么去使用它,以及它的实现类有哪些,有什么区别,初始化的过程又是什么?
ApplicationContext就是IOC容器,是提供IOC容器应用配置的普通接口。
下面看下ApplicationContext这个接口:
公共 接口 ApplicationContext 扩展 EnvironmentCapable,ListableBeanFactory,HierarchicalBeanFactory,
MessageSource,ApplicationEventPublisher,ResourcePatternResolver {
}
复制代码
下面是ApplicationContext这个接口提供的方法:
具体的作用如下:
ApplicationContext 的父级接口
从上面的源码可以看到,ApplicationContext的父级接口也有很多:
下面是每个父级接口的作用:
下面是UML类图:
环境接口,是表示整个应用程序在运行的环境,为了更形象地理解环境接口,可以把春天的运行环境演练成两部分,是春天应用程序,另一部分就是春天应用程序的环境。
HierarchicalBeanFactory接口,获取父工厂,自己子父,包含LocalBean方法是判断本工厂是否包含某个Bean的:
公共 接口 HierarchicalBeanFactory 扩展 BeanFactory {
/**
* 返回父 bean 工厂,如果没有,则返回 { @code null}。
*/
@Nullable
BeanFactory getParentBeanFactory () ;
/**
* 返回本地 bean 工厂是否包含给定名称的 bean,
* 忽略祖先上下文中定义的 bean。
* <p>这是{ @code containsBean}的替代,忽略bean
* 来自祖先 bean 工厂的给定名称。
* @param name 要查询的bean的名称
* @return本地工厂中是否定义了给定名称的bean
* @see BeanFactory#containsBean
*/
boolean containsLocalBean (String name) ;
}
复制代码
ApplicationContext的实现体系
从上图可以看到,AbstractApplicationContext之后是两个部分,一部分是XML的实现,另一部分通用的实现。
- ConfigurableApplicationContext接口
公共 接口 ConfigurableApplicationContext 扩展了 ApplicationContext、Lifecycle、Closeable {
...
}
复制代码
从上图可以看到,ConfigurableApplicationContext接口里面提供了很多的设置方法,而ApplicationContext接口中只有获取方法,所以可以知道,ConfigurableApplicationContext接口是可以配置的ApplicationContext,提供了父容器、环境、BeanFactory后置处理器、监听器等配置方法。
还提供了获取ConfigurableListableBeanFactory的方法,并且实现了生命周期、可关闭的接口,这意味着它能够进行生命周期的控制和关闭的操作。
- AbstractApplicationContext抽象实现类
公共抽象 类 AbstractApplicationContext 扩展 DefaultResourceLoader
实现ConfigurableApplicationContext {
...
}
复制代码
AbstractApplicationContext继承了DefaultResourceLoader,默认为classpath资源加载器
查看源码可以看到,这个类实现了很多的通用方法,包括ApplicationContext、ConfigurableApplicationContext、BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ResourcePatternResolver、Lifecycle 8个父接口的方法实现,主要的目的就是为子类的实现了大量的减负,大部分遗留了refreshBeanFactory、closeBeanFactory、getBeanFactory方法,这三个是具体的子类来实现的
//------------------------------------------------ ---------------------
// 必须由子类实现的抽象方法
//----------------- -------------------------------------------------- ——
protected abstract void refreshBeanFactory () 抛出BeansException, IllegalStateException;
受保护的 抽象 void closeBeanFactory () ;
@覆盖
公共 抽象ConfigurableListableBeanFactory方法getBeanFactory () 抛出IllegalStateException异常;
复制代码
从AbstractApplicationContext之后就出现了一个分支:AbstractRefreshableApplicationContext、GenericApplicationContext
- AbstractRefreshableApplicationContext 类
* @author Juergen Hoeller
* @author克里斯·比姆斯
* @自 1.1 起。3
* @see #loadBeanDefinitions
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
* @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
* @see AbstractXmlApplicationContext
* @see ClassPathXmlApplicationContext
* @see FileSystemXmlApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
*/
公共抽象类 AbstractRefreshableApplicationContext 扩展 AbstractApplicationContext {
}
复制代码
自1.1.3版本提供了抽象实现,提供了工厂刷新方法的实现,可以配置是否可以重写Bean定义以及依赖循环
- AbstractRefreshableConfigApplicationContext 类
公共抽象 类 AbstractRefreshableConfigApplicationContext 扩展 AbstractRefreshableApplicationContext
实现BeanNameAware , InitializingBean {
}
复制代码
AbstractRefreshableConfigApplicationContext则增加了资源配置入口,通过环境解析出配置的真实资源路径字符串。
- 抽象XmlApplicationContext
公共抽象 类 AbstractXmlApplicationContext 扩展 AbstractRefreshableConfigApplicationContext {
}
复制代码
AbstractXmlApplicationContext里面主要实现了一些Bean定义的加载
ClassPathXmlApplicationContext、FileSystemXmlApplicationContext是xml资源加载方式的具体实现
- 通用应用上下文
公共类 GenericApplicationContext 扩展 AbstractApplicationContext 实现 BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
}
复制代码
它实现了BeanDefinitionRegistry接口,该定义接口了bean定义信息的注册行为。 即我们可以直接往GenericApplicationContext中注册bean定义
@Override
public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition)
抛出BeanDefinitionStoreException {
这个.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
复制代码
相关实现有:
AnnotationConfigApplicationContext 注解配置
GenericGroovyApplicationContext groovy方式配置
GenericXmlApplicationContext 通用的xml配置
StaticApplicationContext 动态资源配置方式
从源码可以抽象AbstractRefreshApplicationContext是继承式扩展扩展,GenericApplicationContext则是组合式扩展
同类使用的例子:
@Configuration
@ComponentScan ( "edu.dongnao.courseware" )
公共 类 应用{
公共 静态 无效主(字符串 [] args){
ApplicationContext context = new ClassPathXmlApplicationContext( "application.xml" );
拉德CS = context.getBean(“SWK” ,拉德。类);
cs.sayLove();
ApplicationContext context1 = new FileSystemXmlApplicationContext( "F:/workspace/idea/vip/spring-source/src/main/resources/application.xml" );
CS = context1.getBean(“LAD” ,拉德。类);
cs.sayLove();
context1 = new GenericXmlApplicationContext( "file:F:/workspace/idea/vip/spring-source/src/main/resources/application.xml" );
cs = context1.getBean( "swk" , Lad. class );
cs.sayLove();
//注解的方式
的ApplicationContext上下文2 =新AnnotationConfigApplicationContext(应用类);
拉德CS2 = context2.getBean(拉德。类);
cs2.sayLove();
System.out.println( "------------------------------------------- -----------" );
GenericApplicationContext context3 = new GenericApplicationContext();
new XmlBeanDefinitionReader(context3).loadBeanDefinitions( "classpath:application.xml" );
new ClassPathBeanDefinitionScanner(context3).scan( "edu.dongnao.courseware" );
// 一定要刷新
context3.refresh();
cs2 = context3.getBean( "swk" , Lad. class );
cs2.sayLove();
MagicGril AB = context3.getBean(MagicGril。类);
ab.start();
// 最好跟GenericApplicationContext一样
// ApplicationContext context4 = new StaticApplicationContext();
}
}
复制代码
ApplicationContext的初始化过程
以ClassPathXmlApplicationContext为例:
追踪代码路径:
刷新方法是一个正确的部分,里面的每一个方法都是很重要的步骤:
@Override
public void refresh () throws BeansException, IllegalStateException {
synchronized ( this .startupShutdownMonitor) {
// 准备刷新上下文。
//为刷新做准备,初始化各种状态,启动时间、关闭激活状态、配置文件信息等
准备刷新();
// 告诉子类刷新内部 bean 工厂。
//通知子类刷新内部的BeanFactory,并且返回刷新后的BeanFactory
//可以关注下
刷新BeanFactory ,两个子类对它刷新的多样性// AbstractRefreshableApplicationContext#refreshBeanFactory中重新构建,完成BeanDefinition构建的解析 // GenericApplicationContext #refreshBeanFactory则是设置ID,只能刷新一次
ConfigurableListableBeanFactory beanFactory = becomeFreshBeanFactory();
// 准备在此上下文中使用的 bean 工厂。
//给容器准备BeanFactory,并且配置相关的属性
准备BeanFactory(beanFactory);
try {
// 允许在上下文子类中对 bean 工厂进行后处理。
//允许子类处理后置BeanFactory
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为 bean 的工厂处理器。
//调用注册了BeanFactory后置处理器接口实例Bean对应的方法
调用BeanFactoryPostProcessors(beanFactory);
// 注册拦截 bean 创建的 bean 处理器。
//注册bean后置处理器接口的实例bean
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
//初始化国际化资源
initMessageSource();
// 为此上下文初始化事件多播器。
//初始化事件传播者
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊 bean。
//刷新事件,初始化一些指定的bean
onRefresh();
// 检查侦听器 bean 并注册它们。
//注册监听器bean
注册监听器();
// 实例化所有剩余的(非延迟初始化)单例。
//完成bean工厂的初始化,初始化所有非懒加载的单例bean
完成BeanFactoryInitialization(beanFactory);
// 最后一步:发布对应的事件。
//最后,发布finishRefresh事件
完成刷新();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn( "上下文初始化时遇到异常 -" +
"取消刷新尝试:" + ex);
}
// 销毁已经创建的单例以避免悬空资源。
//已经所有已经创建了的单例豆
销毁Beans();
// 重置“活动”标志。
//灯光激活
取消刷新(前);
// 将异常传播给调用者。
扔前;
}
finally {
// 重置 Spring 核心中的常见内省缓存,因为我们
// 可能不再需要单例 bean 的元数据...
resetCommonCaches();
}
}
}
复制代码
本篇内容是对ApplicationContext的源码做一些简单的了解,以及对初始化过程的了解,即将进行源码的分析。
相关推荐
- js向对象中添加元素(对象,数组) js对象里面添加元素
-
一、添加一个元素对象名["属性名"]=值(值:可以是一个值,可以是一个对象,也可以是一个数组)这样添加进去的元素,就是一个值或对象或数组...
- JS小技巧,如何去重对象数组?(一)
-
大家好,关于数组对象去重的业务场景,想必大家都遇到过类似的需求吧,这对这样的需求你是怎么做的呢。下面我就先和大家分享下如果是基于对象的1个属性是怎么去重实现的。方法一:使用.filter()和....
- 「C/C++」之数组、vector对象和array对象的比较
-
数组学习过C语言的,对数组应该都不会陌生,于是这里就不再对数组进行展开介绍。模板类vector模板类vector类似于string,也是一种动态数组。能够在运行阶段设置vector对象的长度,可以在末...
- 如何用sessionStorage保存对象和数组
-
背景:在工作中,我将[{},{}]对象数组形式,存储到sessionStorage,然后ta变成了我看不懂的形式,然后我想取之用之,发现不可能了~记录这次深刻的教训。$clickCouponIndex...
- JavaScript Array 对象 javascript的array对象
-
Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...
- JavaScript中的数组Array(对象) js array数组
-
1:数组Array:-数组也是一个对象-数组也是用来存储数据的-和object不同,数组中可以存储一组有序的数据,-数组中存储的数据我们称其为元素(element)-数组中的每一个元素都有一...
- 数组和对象方法&数组去重 数组去重的5种方法前端
-
列举一下JavaScript数组和对象有哪些原生方法?数组:arr.concat(arr1,arr2,arrn);--合并两个或多个数组。此方法不会修改原有数组,而是返回一个新数组...
- C++ 类如何定义对象数组?初始化数组?linux C++第43讲
-
对象数组学过C语言的读者对数组的概念应该很熟悉了。数组的元素可以是int类型的变量,例如int...
- ElasticSearch第六篇:复合数据类型-数组,对象
-
在ElasticSearch中,使用JSON结构来存储数据,一个Key/Value对是JSON的一个字段,而Value可以是基础数据类型,也可以是数组,文档(也叫对象),或文档数组,因此,每个JSON...
- 第58条:区分数组对象和类数组对象
-
示例设想有两个不同类的API。第一个是位向量:有序的位集合varbits=newBitVector;bits.enable(4);bits.enable([1,3,8,17]);b...
- 八皇后问题解法(Common Lisp实现)
-
如何才能在一张国际象棋的棋盘上摆上八个皇后而不致使她们互相威胁呢?这个著名的问题可以方便地通过一种树搜索方法来解决。首先,我们需要写一个函数来判断棋盘上的两个皇后是否互相威协。在国际象棋中,皇后可以沿...
- visual lisp修改颜色的模板函数 怎么更改visual studio的配色
-
(defunBF-yansemokuai(tuyuanyanse/ss)...
- 用中望CAD加载LISP程序技巧 中望cad2015怎么加载燕秀
-
1、首先请加载lisp程序,加载方法如下:在菜单栏选择工具——加载应用程序——添加,选择lisp程序然后加载,然后选择添加到启动组。2、然后是添加自定义栏以及图标,方法如下(以...
- 图的深度优先搜索和广度优先搜索(Common Lisp实现)
-
为了便于描述,本文中的图指的是下图所示的无向图。搜索指:搜索从S到F的一条路径。若存在,则以表的形式返回路径;若不存在,则返回nil。...
- 两个有助于理解Common Lisp宏的例子
-
在Lisp中,函数和数据具有相同的形式。这是Lisp语言的一个重大特色。一个Lisp函数可以分析另一个Lisp函数;甚至可以和另一个Lisp函数组成一个整体,并加以利用。Lisp的宏,是实现上述特色的...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- patch补丁 (31)
- strcat (25)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- element style (30)
- dedecms模版 (53)
- vs打不开 (29)
- nmap (30)
- webgl开发 (24)
- parse (24)
- c 视频教程下载 (33)
- android 开发环境 (24)
- paddleocr (28)
- listview排序 (33)
- firebug 使用 (31)
- transactionmanager (30)
- characterencodingfilter (33)
- getmonth (34)
- commandtimeout (30)
- hibernate教程 (31)
- label换行 (33)