当前位置: 首页 > news >正文

Spring源码阅读-ApplicationContext

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

ApplicationContext  vs   BeanFactory

beanFactory就是一个容器,它的工作就是实例化、依赖注入,但是仅仅只是这样用户使用比较麻烦,很多事还需要自己做,比如通过Resource加载配置、注册扩展点、添加监听器等等,所以spring提供了一些常用的应用上下文ApplicationContext来帮助用户快速开发,ApplicationContext在beanFactory的基础之上做了扩展,它包含beanFactory的所有功能,并初始化了很多默认功能。

AbstractApplicationContext

ApplicationContext也有很多实现类,这里选取一个常用的ClassPathXmlApplicationContext做测试,跟踪他的构造方法:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {

	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

设置好配置配置文件路径后就进入到refresh方法中,这个refresh方法是在上层抽象类AbstractApplicationContext中,先看一下refresh整体流程:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		// 准备上下文
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		// 读取配置文件初始化beanFactory(加载bean, loadBeanDefinitions)
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		// 上面BeanFactory加载完毕,下面开始ApplicationContext的扩展
		//额外填充beanFactory
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			// 给子类覆盖用的,子类可以对BeanFactory做一些处理
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			//执行BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			//扩展点BeanPostProcessor的注册,在BeanFactory getBean的时候会调用
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			// 初始化message源, 国际化处理
			initMessageSource();

			// Initialize event multicaster for this context.
			// 注册applicationEventMulticaster
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context
			// subclasses.
			onRefresh();//留给子类初始化

			// Check for listener beans and register them.
			//注册监听器
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			//实例化对象,对于那些非懒加载的单例
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			//收尾
			finishRefresh();
		}
		catch (BeansException ex) {
			logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}
	}
}

这块代码流程一看就比较清晰,依次看每块实现逻辑:

prepareRefresh

protected void prepareRefresh() {
	this.startupDate = System.currentTimeMillis();
	//状态标识
	synchronized (this.activeMonitor) {
		this.active = 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();
}

初始化之前的准备,这个方法很简单,设置标志,准备初始化参数,验证必要的参数,initPropertySources留给子类扩展的。

obtainFreshBeanFactory

这步就是获取beanFactory,这个操作委托给了refreshBeanFactory方法,继续看代码:

protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		//根据当前context的特点对其内部的beanFactory设置属性
		customizeBeanFactory(beanFactory);
		// 这个里面就是通过XmlBeanDefinitionReader加载配置到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);
	}
}

先关闭之前的beanFactory,再创建新的,并根据当前上下文特点对beanFactory设置一些初始化特性参数,然后加载bean的配置。

customizeBeanFactory方法中设置参数,这里主要包括两个参数:    allowBeanDefinitionOverriding允许bean名称重复,后面的覆盖前面的,默认开启、关闭后遇到相同的beanName直接抛异常,allowCircularReferences设置允许循环引用

loadBeanDefinitions方法里面用BeanDefinitionReader读取配置解析加载到beanFactory的BeanDefinitions中,这里就是beanFactory的启动了,从这里也可以看出ApplicationContext做的事情要比 beanFactory多。

prepareBeanFactory

这步就是根据当前应用上下文ApplicationContext配置它内部beanFactory的特色,具体特色还是看代码:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	beanFactory.setBeanClassLoader(getClassLoader());
	//el表达式 #{}
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
	//属性转换器
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	
	//autowireByName autowireByType忽略?
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	//这些不作为可解析的类型,直接把对应的注入value放到集合中
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	// AspectJ
	//一个内置扩展点, 主要用于注入LoadTimeWeaver
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register default environment beans.
	//注册默认的环境bean
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}
  1. ClassLoader:使用自己的类加载器
  2. BeanExpressionResolver:el表达式解析器,配置中使用#{xxx}
  3. ResourceEditorRegistrar: 属性转换器,比如定义属性为Date,配置文件中配置成字符串,就是通过这个里面的功能把它转换过来的,spring内置了很多属性编辑器。
  4. Aware-processors:对实现了对象的Aware接口注入,如:EnvironmentAware、ApplicationEventPublisherAware、ApplicationContextAware等等。
  5. ignoreDependencyInterface:忽略依赖注入的接口,这步跟第4步是对应的,上面处理了这里就忽略,默认只有BeanFactoryAware,可以调用该方法往忽略集合里面添加。
  6. registerResolvableDependency:如果注入的时候遇到这些类型,不去解析他们而是直接取对应固定的value值
  7. LoadTimeWeaverAwareProcessor: 设置扩展点,如果过bean实现LoadTimeWeaverAware接口,则LoadTimeWeaver对象注入到bean中,LoadTimeWeaver这里涉及到aop相关的概念(spring中实现aop用了好几种方式)
  8. 注册默认环境bean: environment、systemProperties、systemEnvironment

postProcessBeanFactory

上面是spring根据当前ApplicationContext做了很多设定,如果用户自定义ApplicationContext可以重写postProcessBeanFactory做其他设置,这里默认实现为空就是留给子类实现的。

invokeBeanFactoryPostProcessors

执行BeanFactoryPostProcessor,这个也是spring的开闭原则,必须在bean实例化之前执行,BeanFactoryPostProcessor的方法postProcessBeanFactory参数是beanFactory,这些后处理器可以对beanFactory进行修改,所以bean实例化之后再做这边就没有意义了。

registerBeanPostProcessors

扩展点BeanPostProcessor的注册,在BeanFactory getBean的时候会调用

initMessageSource

常用作国际化,spring里面处处都是bean,这里也一样,定义一个MessageSource的bean,在用到该功能的时候获取该bean。

initApplicationEventMulticaster

初始化event multicaster,广播所有事件到所有注册的监听器,让它们自己忽略不感兴趣的事件,默认实现类为SimpleApplicationEventMulticaster,它里面会让所有监听器在当前线程执行,这就有可能某个监听器阻塞整个应用,所有第二种方式是可以指定一个任务执行线程池来执行这些监听器。

onRefresh

留给子类实现,对于指定的bean可以进行特殊初始化

registerListeners

注册监听器到EventMulticaster中,用于接收EventMulticaster的消息,所有实现了ApplicationListener接口的都算,并且不需要提前初始化,

protected void registerListeners() {
	// Register statically specified listeners first.
	//先把已经指定的添加
	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!
	//再把未初始化的添加
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String lisName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(lisName);
	}
}

finishBeanFactoryInitialization

在上下文中bean工厂初始化好了之后对里面必要的bean进行初始化

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	// 初始化类型转换服务
	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));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	// 先初始化实现了LoadTimeWeaverAware接口的bean
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}
	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	//冻结配置,不允许在修改了
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	// 根据条件(非静态、单例、非懒加载)遍历所有beanName实例化
	beanFactory.preInstantiateSingletons();
}

这里最先初始化了类型转换服务,这个服务在后面getBean的时候需要用到类型转换,所以放在第一位,第二位初始化的是实现了LoadTimeWeaverAware的bean,这个里面涉及的比较多,要后面专门开篇,最后实例化满足非静态、单例、非懒加载三个条件的bean。

finishRefresh

protected void finishRefresh() {
	// Initialize lifecycle processor for this context.
	// 初始化lifecycle processor , 默认DefaultLifecycleProcessor
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	// 
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

最后完成ApplicationContext初始化后要初始化一下生命周期处理类,默认DefaultLifecycleProcessor,然后调用它的onRefresh,这里引出另外一个概念:生命周期,spring中Lifecycle接口为生命周期接口,bean只要实现这个接口,在ApplicationContext初始化、销毁后会收到对应的通知,这也是ApplicationContext跟业务bean交互的一种方式。

最后发布上下文启动完毕的通知。

异常结束

如果在初始化的过程中出现了异常,spring会捕获该异常,并把已经创建的单例对象销毁,重置启动状态标志位

总结

spring中以BeanFactory为核心,它的里面处处都是以bean的形式存在,比如国际化资源,事件广播器,生命周期处理器等等都是以bean的形式注册在beanFactory上的,在该核心的基础之上封装了好几种应用上下文,用户通常是通过应用上下文的方式使用。

转载于:https://my.oschina.net/chengxiaoyuan/blog/829175

相关文章:

  • linux系统下查看网卡的UUID
  • String类型的方法总结
  • 通过Servlet生成验证码图片(转)
  • C#实现MD5字符串加密
  • 集成软件开发工具有多难?现实很残酷!
  • bzoj2333
  • rpm的含义
  • 使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码...
  • 兄弟选择器 + 和 ~
  • 在Mac OS X 10.8中配置Apache + PHP + MySQL
  • Docker学习笔记 - Docker的远程访问
  • 2015-02-01
  • 连续自然数和
  • php中的in_array分析及其替换方法
  • Linux内核 设备树操作常用API
  • 【Linux系统编程】快速查找errno错误码信息
  • avalon2.2的VM生成过程
  • canvas 高仿 Apple Watch 表盘
  • dva中组件的懒加载
  • Effective Java 笔记(一)
  • If…else
  • Intervention/image 图片处理扩展包的安装和使用
  • Map集合、散列表、红黑树介绍
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 复杂数据处理
  • 基于遗传算法的优化问题求解
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 探索 JS 中的模块化
  • 微服务入门【系列视频课程】
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 主流的CSS水平和垂直居中技术大全
  • # include “ “ 和 # include < >两者的区别
  • $(function(){})与(function($){....})(jQuery)的区别
  • $(selector).each()和$.each()的区别
  • (16)Reactor的测试——响应式Spring的道法术器
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (三)mysql_MYSQL(三)
  • (十六)Flask之蓝图
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • *2 echo、printf、mkdir命令的应用
  • .NET连接MongoDB数据库实例教程
  • .net连接oracle数据库
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • @EnableConfigurationProperties注解使用
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • []指针
  • [20150629]简单的加密连接.txt
  • [20171113]修改表结构删除列相关问题4.txt
  • [20190416]完善shared latch测试脚本2.txt
  • [AutoSar NVM] 存储架构
  • [BJDCTF2020]The mystery of ip