[spring源码学习]七、IOC源码-Context
一、代码实例
如之前介绍的,spring中ioc是它最为核心的模块,前边花了大量时间分析spring的bean工厂和他如何生成bean,可是在我们实际应用中,很少直接使用beanFactory,因为spring提供了更好用的ApplicationContext接口,使用方法和bean工厂基本一致
- ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
- Person person=(Person)context.getBean("person");
- person.sayHello();
那么我们来看下源代码中,我们ClassPathXmlApplicationContext为目标,分析它做了哪些工作。
二、源码分析
1、进入ClassPathXmlApplicationContext,我们可以看到他提供了各种重构方法,其中配置文件路径可以支持:字符串,可变字符串,数组
- public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
- this(new String[] {configLocation}, true, null);
- }
- public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
- this(configLocations, true, null);
- }
- public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
- this(configLocations, true, parent);
- }
- public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
- this(configLocations, refresh, null);
- }
2、进入refresh方法,首先竹本refresh环境,
- protected void prepareRefresh() {
- this.startupDate = System.currentTimeMillis();
- this.closed.set(false);
- this.active.set(true);
- if (logger.isInfoEnabled()) {
- logger.info("Refreshing " + this);
- }
- // Initialize any placeholder property sources in the context environment
- initPropertySources();
- // Validate that all properties marked as required are resolvable
- // see ConfigurablePropertyResolver#setRequiredProperties
- getEnvironment().validateRequiredProperties();
- // Allow for the collection of early ApplicationEvents,
- // to be published once the multicaster is available...
- this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
- }
3、调用ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
- protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
- refreshBeanFactory();
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (logger.isDebugEnabled()) {
- logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
- }
- return beanFactory;
- }
4、调用refreshBeanFactory方法,可以看到里边的几个步骤
a)生产beanfactory,如果有父类,继承父类
b)设置序列化id
c)customizeBeanFactory,暂时不知道用处
d)loadBeanDefinitions(beanFactory)最终调用了loadBeanDefinitions(beanDefinitionReader)方法
可见在此步骤已经完成了对xml文件的读取,并解析为最终的beanDefinition
- protected final void refreshBeanFactory() throws BeansException {
- if (hasBeanFactory()) {
- destroyBeans();
- closeBeanFactory();
- }
- try {
- DefaultListableBeanFactory beanFactory = createBeanFactory();
- beanFactory.setSerializationId(getId());
- customizeBeanFactory(beanFactory);
- loadBeanDefinitions(beanFactory);
- synchronized (this.beanFactoryMonitor) {
- this.beanFactory = beanFactory;
- }
- }
- catch (IOException ex) {
- throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
- }
- }
5、prepareBeanFactory设置各种BeanFactory的参数
6、invokeBeanFactoryPostProcessors调用BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的方法
7、查找是否有initMessageSource为id的bean,如果没有,创建默认的
8、查找是否有id为applicationEventMulticaster的bean,如果没有,创建默认,设置为congtext的applicationEventMulticaster
- protected void initApplicationEventMulticaster() {
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- //查找是否包含名为applicationEventMulticaster的bean,如果没有,创建默认的
- if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
- this.applicationEventMulticaster =
- beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
- if (logger.isDebugEnabled()) {
- logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
- }
- }
- else {
- this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
- beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
- if (logger.isDebugEnabled()) {
- logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
- APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
- "': using default [" + this.applicationEventMulticaster + "]");
- }
- }
- }
9、查找注册的ApplicationListener,设置到applicationEventMulticaster中
- protected void registerListeners() {
- // Register statically specified listeners first.
- //查找手动设置的ApplicationListener,设置到applicationEventMulticaster中
- for (ApplicationListener<?> listener : getApplicationListeners()) {
- getApplicationEventMulticaster().addApplicationListener(listener);
- }
- // Do not initialize FactoryBeans here: We need to leave all regular beans
- // uninitialized to let post-processors apply to them!
- //根据beanType查询ApplicationListener,设置到applicationEventMulticaster中
- String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
- for (String listenerBeanName : listenerBeanNames) {
- getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
- }
- // Publish early application events now that we finally have a multicaster...
- Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
- //查询是否有需要立即通知的事件,进行通知
- this.earlyApplicationEvents = null;
- if (earlyEventsToProcess != null) {
- for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
- getApplicationEventMulticaster().multicastEvent(earlyEvent);
- }
- }
- }
10、查找是否有id为conversionService的bean,如果有,设置进beanFactory
- //查找是否有id为conversionService的bean,如果有,设置进beanFactory
- if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
- beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
- beanFactory.setConversionService(
- beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
- }
11、查找是否有embeddedValueResolvers,值的解析器,没有默认注入string解析
- //查找是否有embeddedValueResolvers,值的解析器,没有默认注入string解析
- if (!beanFactory.hasEmbeddedValueResolver()) {
- beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
- @Override
- public String resolveStringValue(String strVal) {
- return getEnvironment().resolvePlaceholders(strVal);
- }
- });
- }
12、查找类型为LoadTimeWeaverAware的解析,有的话进行获取,并没有进一步使用,应该只是起到初始化作用
- //查找类型为LoadTimeWeaverAware的解析,有的话进行获取,并没有进一步使用,应该只是起到初始化作用
- String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
- for (String weaverAwareName : weaverAwareNames) {
- getBean(weaverAwareName);
- }
13、进入preInstantiateSingletons方法,初始化所有的bean
- for (String beanName : beanNames) {
- RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
- if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
- //判断是否工厂bean
- if (isFactoryBean(beanName)) {
- final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
- boolean isEagerInit;
- if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
- isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
- @Override
- public Boolean run() {
- return ((SmartFactoryBean<?>) factory).isEagerInit();
- }
- }, getAccessControlContext());
- }
- else {
- isEagerInit = (factory instanceof SmartFactoryBean &&
- ((SmartFactoryBean<?>) factory).isEagerInit());
- }
- if (isEagerInit) {
- getBean(beanName);
- }
- }
- else {
- //进行实例化
- getBean(beanName);
- }
- }
- }
14、已经初始化的bean,并且继承了SmartInitializingSingleton接口,执行它的afterSingletonsInstantiated方法
- //已经初始化的bean,并且继承了SmartInitializingSingleton接口,执行它的afterSingletonsInstantiated方法
- for (String beanName : beanNames) {
- Object singletonInstance = getSingleton(beanName);
- if (singletonInstance instanceof SmartInitializingSingleton) {
- final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
- if (System.getSecurityManager() != null) {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- @Override
- public Object run() {
- smartSingleton.afterSingletonsInstantiated();
- return null;
- }
- }, getAccessControlContext());
- }
- else {
- smartSingleton.afterSingletonsInstantiated();
- }
- }
- }
15、调用finishRefresh,完成bean的刷新,第一步initLifecycleProcessor初始化bean的生命后周期bean
- protected void initLifecycleProcessor() {
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- //获取id为lifecycleProcessor的bean,如果没有,创建默认的
- if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
- this.lifecycleProcessor =
- beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
- if (logger.isDebugEnabled()) {
- logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
- }
- }
- else {
- DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
- defaultProcessor.setBeanFactory(beanFactory);
- this.lifecycleProcessor = defaultProcessor;
- beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
- if (logger.isDebugEnabled()) {
- logger.debug("Unable to locate LifecycleProcessor with name '" +
- LIFECYCLE_PROCESSOR_BEAN_NAME +
- "': using default [" + this.lifecycleProcessor + "]");
- }
- }
- }
16、getLifecycleProcessor().onRefresh()方法,启动特定bean
- private void startBeans(boolean autoStartupOnly) {
- Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
- //获取所有继承了Lifecycle的SmartLifecycle,并且自动启动且phase不为空,那么执行start方法
- Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
- for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
- Lifecycle bean = entry.getValue();
- if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
- int phase = getPhase(bean);
- LifecycleGroup group = phases.get(phase);
- if (group == null) {
- group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
- phases.put(phase, group);
- }
- group.add(entry.getKey(), bean);
- }
- }
- if (phases.size() > 0) {
- List<Integer> keys = new ArrayList<Integer>(phases.keySet());
- Collections.sort(keys);
- for (Integer key : keys) {
- phases.get(key).start();
- }
- }
- }
17、广播容器刷新事件publishEvent(new ContextRefreshedEvent(this))
- protected void publishEvent(Object event, ResolvableType eventType) {
- Assert.notNull(event, "Event must not be null");
- if (logger.isTraceEnabled()) {
- logger.trace("Publishing event in " + getDisplayName() + ": " + event);
- }
- // Decorate event as an ApplicationEvent if necessary
- ApplicationEvent applicationEvent;
- if (event instanceof ApplicationEvent) {
- applicationEvent = (ApplicationEvent) event;
- }
- else {
- applicationEvent = new PayloadApplicationEvent<Object>(this, event);
- if (eventType == null) {
- eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
- }
- }
- // Multicast right now if possible - or lazily once the multicaster is initialized
- if (this.earlyApplicationEvents != null) {
- //如果有预制行添加到预制行,预制行在执行一次后被置为null,以后都是直接执行
- this.earlyApplicationEvents.add(applicationEvent);
- }
- else {
- //广播event时间
- getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
- }
- // Publish event via parent context as well...
- //父bean同样广播
- if (this.parent != null) {
- if (this.parent instanceof AbstractApplicationContext) {
- ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
- }
- else {
- this.parent.publishEvent(event);
- }
- }
- }
18、到此,我们完成了整个初始化过程,获取bean时候,流程基本不变
三、总结
我们可以看到,与beanfactory相比,context有以下特点:
1、在基本的解析文件生成beanDefinition过程其实两者是一致的,都是解析了xml的配置后生成了配置文件放到了beanDefinitionMap中
2、在beanFactory中的,bean是在第一次getBean的时候进行生成,所以配置lazy-init延迟加载并不会起作用,因为全部bean都是延迟加载的。在context中,会在解析完成后的preInstantiateSingletons方法中调用getBean初始化所有的非lazy-init且单例模式的bean
3、在context中内置了许多的bean,他们要求开发者必须按照系统约定的命名规则进行命名,这样可以在系统内部组成特定的功能,如果开发者没有定义这些bean,系统也会默认生成一个bean,这些bean主要有:messageSource、applicationEventMulticaster、conversionService、embeddedValueResolvers、lifecycleProcessor,也有一些指定了接口实现的bean如:LoadTimeWeaverAware、SmartInitializingSingleton。这些类完善了bean的整个流程,使得ioc容器可以读取配置文件,管理通知,bean生命周期等
[spring源码学习]七、IOC源码-Context的更多相关文章
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign
基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(一)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(二)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)浅谈 REST 和 CRUD
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- go 源码学习之---Tail 源码分析
已经有两个月没有写博客了,也有好几个月没有看go相关的内容了,由于工作原因最近在做java以及大数据相关的内容,导致最近工作较忙,博客停止了更新,正好想捡起之前go的东西,所以找了一个源码学习 这个也 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- Jetty源码学习-编译Jetty源码二三事
工作小几个月了,JDK基础和web应用框架学的的差不多了,开始学习Jetty源码,费了小半天才编译成功,把自己拆过的坑记录下来. 编译前的环境: MAVEN 3.3.Eclips eLuna Serv ...
- Spring源码学习之IOC容器实现原理(一)-DefaultListableBeanFactory
从这个继承体系结构图来看,我们可以发现DefaultListableBeanFactory是第一个非抽象类,非接口类.实际IOC容器.所以这篇博客以DefaultListableBeanFactory ...
随机推荐
- iOS优秀博客收录
原文链接:http://ju.outofmemory.cn/entry/105297 唐巧 王巍 破船之家 NSHipster Limboy 无网不剩 念茜的博客 Xcode Dev Ted's Ho ...
- [从产品角度学excel 04]-单元格的“衣服”
忘记发这里了..补发一下 这是<从产品角度学EXCEL>系列——单元格篇. 前言请看: 0 为什么要关注EXCEL的本质 1 excel是怎样运作的 2 EXCEL里的树形结构 3 单元格 ...
- JS事件的三种方式
1.直接在元素上绑定回调函数 <button id="btn" onclick="clickBtn()">click me</button&g ...
- SQL Server中查询数据库及表的信息语句
/* -- 本文件主要是汇总了 Microsoft SQL Server 中有关数据库与表的相关信息查询语句. -- 下面的查询语句中一般给出两种查询方法, -- A方法访问系统表,适应于SQL 20 ...
- 关于JS事件的几点总结
1.理解事件(2点) 事件行为本身:没有给事件绑定方法事件也是一直存在的,当触发行为的时候,也对触发对应的行为,只不过由于没有绑定事件,导致没有任何事件发生: 事件绑定:给元素绑定一个方法:触发行为, ...
- 使用CSS隐藏HTML元素的4种常用方法
现在的网页设计越来越动态化,我们经常需要隐藏某些元素,在特定的时候才显示它们.我们通常可以使用4种方法来隐藏和显示元素. 这4种显示和隐藏元素的技术各自有它们自己的优点的缺点,下面来举例说明. 在这篇 ...
- C#微信公众号开发系列教程二(新手接入指南)
http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...
- Gerrit增加SSL证书
在http的基础上增加SSL 配置gerrit.config文件 [gerrit] basePath = git canonicalWebUrl = https://172.16.99.212/ .. ...
- pg gem 安装(postgresql94)
使用下面命令安装报错 gem install pg 错误: [root@AS-test middle_database]# gem install pgBuilding native extensio ...
- Windows10系统如何更改程序的默认安装目录?
Windows10系统如何更改程序的默认安装目录? 在Windows10系统的使用中,软件程序的默认安装目录是:C:\Program Files\...或者C:\Program Files(x86)\ ...