Spring ApplicationContext上下文核心容器深入探究

目录
  • 整体流程
    • prepareRefresh
    • obtainFreshBeanFactory
    • prepareBeanFactory
    • postProcessBeanFactory
  • 总结

Spring 容器核心可归纳为两个类: BeanFactory 和 ApplicationContext,ApplicationContext 继承自 BeanFactory ,其不仅包含 BeanFactory 所有功能,还扩展了容器功能。ApplicationContext 核心其实是 refresh 方法,容器一系列功能都在该方法中实现,如:注册 Bean、注入 Bean 等。

整体流程

refresh 方法定义在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象类实现,该方法由十几个子方法组成,这些子方法各司其职完成容器的初始化。

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	......
	//加载或刷新配置的持久表示形式,
    //可能是XML文件、属性文件或关系数据库模式。
    //由于这是一个启动方法,它应该销毁已经创建的单例
    //如果失败,则避免悬而未决的资源。换句话说,在调用该方法之后,要么全部实例化,要么根本不实例化。
    //如果无法初始化bean工厂,则抛出BeanException异常,抛出IllegalStateException异常
    //如果已初始化且不支持多次刷新尝试
	void refresh() throws BeansException, IllegalStateException;
    ......
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
    ......
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 准备此上下文以进行刷新
			prepareRefresh();
			// 告诉子类刷新内部bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 准备bean工厂,以便在此上下文中使用
			prepareBeanFactory(beanFactory);
			try {
				// 允许在上下文子类中对bean工厂进行后处理
				postProcessBeanFactory(beanFactory);
				// 调用在上下文中注册为bean的工厂处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				// 注册拦截bean创建的bean处理器
				registerBeanPostProcessors(beanFactory);
				// 为此上下文初始化消息源。
				initMessageSource();
				// 为此上下文初始化事件多播
				initApplicationEventMulticaster();
				// 初始化特定上下文子类中的其他特殊bean
				onRefresh();
				// 检查侦听器bean并注册它们
				registerListeners();
				// 实例化所有剩余的(非懒加载)单例
				finishBeanFactoryInitialization(beanFactory);
				// 最后一步:发布相应的事件
				finishRefresh();
			}
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				// 销毁已创建的单例以避免悬空资源
				destroyBeans();
				// 重置“活动”标志
				cancelRefresh(ex);
				// 将异常传播到调用方
				throw ex;
			}
			finally {
				// 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。。。
				resetCommonCaches();
			}
		}
	}
 ......
}

在spring中AbstractApplicationContext的实现类通过调用父类的方法完成容器的初始化,下文以ClassPathXmlApplicationContext为例来追踪容器的创建流程。

public class contextText {
	ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml");
}
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
......
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}
......
}

refresh 方法中,前四个子方法主要进行上下文准备工作。

prepareRefresh

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 初始化上下文环境,就是记录下容器的启动时间、活动状态等
		prepareRefresh();
		...
    }
}
public abstract class AbstractApplicationContext {
    ...
    private long startupDate;
    private final AtomicBoolean active = new AtomicBoolean();
	private final AtomicBoolean closed = new AtomicBoolean();
    private Set<ApplicationEvent> earlyApplicationEvents;
    ...
    protected void prepareRefresh() {
        // 记录此上下文开始时的系统时间(以毫秒为单位)
    	this.startupDate = System.currentTimeMillis();
    	// 记录此上下文是否已关闭,这里设置为未关闭
    	this.closed.set(false);
    	// 记录此上下文是否处于活动状态,这里设置为活动状态
    	this.active.set(true);
    	if (logger.isInfoEnabled()) {
    		logger.info("Refreshing " + this);
    	}
    	// 这也是交由子类扩展的方法。具体子类为 GenericWebApplicationContext,主要是初始化属性源,
    	// 将 ServletContext 和 ServletConfig 属性配置添加到 Environment 环境上下文中
    	initPropertySources();
    	// 校验 Environment 中那些必备的属性配置是否存在,不存在则抛异常。
    	getEnvironment().validateRequiredProperties();
    	// 创建 ApplicationEvent 事件集合
    	this.earlyApplicationEvents = new LinkedHashSet<>();
    }
}

refresh 中的 prepareRefresh 方法执行结束,主要是记录容器的启动时间、活动状态、检查必备属性是否存在。

obtainFreshBeanFactory

public abstract class AbstractApplicationContext {
    ...
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		...
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    		...
    	}
    }
    ...
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 该方法也是由子类扩展,其子类有 AbstractRefreshableApplicationContext 和 GenericApplicationContext,
        // 该方法主要设置 BeanFactory 的 serializationId 属性值,也就是序列化id
    	refreshBeanFactory();
    	// 通过 getBeanFactory 返回 BeanFactory 对象。同样也是由子类扩展,调用的是 GenericApplicationContext 类中的 getBeanFactory 方法。
    	// 返回的是 DefaultListableBeanFactory 。
    	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    	if (logger.isDebugEnabled()) {
    		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    	}
    	return beanFactory;
    }
    ...
}

obtainFreshBeanFactory 方法很简单,因为当前使用的是ClasspathXmlApplicationContext容器类,从类的继承关系可以看出执行的就是 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法,返回的是DefaultListableBeanFactory,之后该方法还返回了 BeanFactory 对象,从这也可以看出 ApplicationContext 底层是以 BeanFactory 为基础,逐步扩展 Spring 容器功能。

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
   ......
	/** Bean factory for this context */
	@Nullable
	private DefaultListableBeanFactory beanFactory;
    ......
	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}
    ......
}

prepareBeanFactory

prepareBeanFactory 方法主要是对 BeanFactory 做一些配置,包含各种类加载器、需要忽略的依赖以及后置处理器、解析器等

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ...
		prepareBeanFactory(beanFactory);
		...
    }
    ...
}
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 设置类加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	// 设置表达式解析器,主要用来解析 EL 表达式; Bean 初始化完成后填充属性时会用到
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	// 设置属性注册解析器,主要用来解析 Bean 中的各种属性类型,如 String、int 等
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
	// 添加一个后置处理器:ApplicationContextAwareProcessor。
	// 该后置处理器用于向实现了 Aware 系列接口的 bean 设置相应属性。
	// (后置处理器和 Aware 接口也是比较核心的概念,后面会有文章详细讨论)
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	// 以下接口,在自动注入时会被忽略,其都是 Aware 系列接口
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	// 当以下特殊的 Bean 需自动注入时,指定其注入的类型 。
	// 如:注入 BeanFactory 时,注入的类型对象为 ConfigurableListableBeanFactory 。
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);
	// 添加 ApplicationListenerDetector 后置处理器。
	// 该后置处理器用来检测那些实现了 ApplicationListener 接口的 bean,并将其添加到应用上下文的事件广播器上。
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
	// 判断容器中是否存在 loadTimeWeaver Bean,如果存在则上下文使用临时的 ClassLoader 进行类型匹配。
	// 集成 AspectJ 时会用到 loadTimeWeaver 对象。
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
	// 注册和环境相关的 Bean,如 environment、systemProperties、systemEnvironment
	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());
	}
}

在 prepareBeanFactory 方法中,主要对 BeanFactory 添加了一系列属性项,如添加忽略自动注入的接口、添加 BeanPostProcessor 后置处理器、手动注册部分特殊的 Bean及环境相关的 Bean 。

postProcessBeanFactory

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ...
        postProcessBeanFactory(beanFactory);
        ...
    }
}

postProcessBeanFactory 方法是上下文准备的最后一步,spring中并没有具体去实现postProcessBeanFactory方法,是提供给想要实现BeanPostProcessor的三方框架使用的。谁要使用谁就去实现。作用是在BeanFactory准备工作完成后做一些定制化的处理,一般结合BeanPostProcessor接口的实现类一起使用,注入一些重要资源(类似Application的属性和ServletContext的属性)。最后需要设置忽略这类BeanPostProcessor子接口的自动装配。

总结

ApplicationContext 上下文准备工作基本结束,主要还是在 BeanFactory 中添加一系列后置处理器、注册特殊的 Bean 及设置忽略自动注入的接口。其中还提到了 Spring 容器的三个核心部分:Aware 系列接口、BeanPostProcessor 后置处理器、BeanDefinition ,这部分在后面的文章会逐步跟踪。

到此这篇关于Spring ApplicationContext上下文核心容器深入探究的文章就介绍到这了,更多相关Spring ApplicationContext内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring系列中的beanFactory与ApplicationContext

    目录 一.BeanFactory 二.ApplicationContext 三.二者区别 四.总结 一.BeanFactory BeanFactory 是 Spring 的“心脏”.它就是 Spring IoC 容器的真面目.Spring 使用 BeanFactory 来实例化.配置和管理 Bean. BeanFactory:是IOC容器的核心接口, 它定义了IOC的基本功能,我们看到它主要定义了getBean方法.getBean方法是IOC容器获取bean对象和引发依赖注入的起点.方法的功能是

  • SpringBoot如何使用applicationContext.xml配置文件

    目录 使用applicationContext.xml配置文件 applicationContext 加载配置文件 案例 多文件的加载方法 使用applicationContext.xml配置文件 SpringBoot默认是通过Java代码进行依赖注入,但也为xml形式的依赖注入提供了入口,就是@ImportResource注解. 我们可以在SpringBoot的启动类上添加这个注解并在注解的locations属性中指定xml配置文件.(可以使用一个文件集合也可以只引入主配置文件然后在主配置文件

  • Spring中BeanFactory和ApplicationContext的作用和区别(推荐)

    作用: 1.BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期.2.ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能: a. 国际化支持 b. 资源访问:Resource rs = ctx. getResource("classpath:config.properties"), "file:c:/config.properties&qu

  • ServletWebServerApplicationContext创建Web容器Tomcat示例

    目录 正文 创建Web服务 一.获取Web服务器工厂 1.1 选择导入Web工厂 二.getWebServer:获取Web服务 2.1 创建TomcatEmbeddedContext 2.2. 创建TomcatWebServer 2.2.1 启动Tomcat 初始化小结 startInternal:启动Internal NamingResources启动 Service启动 启动Engine 启动TomcatEmbeddedContext 启动Executor 启动MapperListener

  • 基于Failed to load ApplicationContext异常的解决思路

    目录 Failed to load ApplicationContext异常 在使用spring连接数据库时出现了如下异常 Failed to load ApplicationContext之spring最常遇到的问题汇总 遇到几个极难解决的问题 Failed to load ApplicationContext异常 在使用spring连接数据库时出现了如下异常 java.lang.IllegalStateException: Failed to load ApplicationContext 

  • SpringBoot项目报错:"Error starting ApplicationContext...."解决办法

    目录 发现错误 一.编译出问题 二.请求接口重复 三.加@Mapper注解 四.加@SpringBootApplication注解,数据库问题 五.端口重复问题 六.包冲突 总结 发现错误 SpringBoot项目报错: Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 以下方案80%可以帮助您解决这些个‘可恶的’问题

  • 一文学透ApplicationContext继承接口功能及与BeanFactory区别

    目录 BeanFactory与ApplicationContext关系的分析 ApplicationContext继承的接口与功能 BeanFactory应用代码示例 ApplicationContext各功能的应用代码示例 ResourceLoader 接口的示例 MessageSource 接口的示例 ApplicationEventPublisher 接口的示例 EnvironmentCapable 接口的示例 ListableBeanFactory接口示例 AutowireCapable

  • 获取Spring的上下文环境ApplicationContext的最简单方式

    目录 获取Spring上下文环境ApplicationContext 分析: 正确的做法是: 注意: Spring上下文(ApplicationContext)理解 什么是Spring应用上下文呢??? 通过.class文件获取bean的方法: 获取Spring上下文环境ApplicationContext Web项目中发现有人如此获得Spring的上下环境: public class SpringUtil { public static ApplicationContext context =

  • Spring核心容器IOC原理实例解析

    这篇文章主要介绍了Spring核心容器IOC原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一 .BeanFactory Spring Bean 的创建是典型的工厂模式,这一系列的 Bean 工厂,也即 IOC 容器为开发者管理对象 间的依赖关系提供了很多便利和基础服务.最基本的 IOC 容器接口 BeanFactory,来看一下它的源码: public interface BeanFactory { //对 FactoryBean

  • 详解Spring Boot最核心的27个注解,你了解多少?

    导读  Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务框架SpringCloud集成. 而Spring Boot之所以能够轻松地实现应用的创建及与其他框架快速集成,最核心的原因就在于它极大地简化了项目的配置,最大化地实现了"约定大于配置"的原则.然而基于Spring Boot虽然极大地方便了开发,但是也很容易让人"云里雾里",特别是各种

  • 浅析Java的Spring框架中IOC容器容器的应用

    Spring容器是Spring框架的核心.容器将创建对象,它们连接在一起,配置它们,并从创建到销毁管理他们的整个生命周期.在Spring容器使用依赖注入(DI)来管理组成应用程序的组件.这些对象被称为Spring Beans. 容器获得其上的哪些对象进行实例化,配置和组装通过阅读提供的配置元数据的说明.配置元数据可以通过XML,Java注释或Java代码来表示.下面的图是Spring如何工作的高层次图. Spring IoC容器是利用Java的POJO类和配置元数据的产生完全配置和可执行的系统或

  • Spring源码分析容器启动流程

    目录 前言 源码解析 1.初始化流程 流程分析 核心代码剖析 2.刷新流程 流程分析 核心代码剖析 前言 本文基于 Spring 的 5.1.6.RELEASE 版本 Spring的启动流程可以归纳为三个步骤: 1.初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中 2.将配置类的BeanDefinition注册到容器中 3.调用refresh()方法刷新容器 Spring Framework 是 Java 语言中影响最为深远的框架之一,其

  • Spring和SpringMVC父子容器关系初窥(小结)

    一.背景 最近由于项目的包扫描出现了问题,在解决问题的过程中,偶然发现了Spring和SpringMVC是有父子容器关系的,而且正是因为这个才往往会出现包扫描的问题,我们在此来分析和理解Spring和SpringMVC的父子容器关系并且给出Spring和SpringMVC配置文件中包扫描的官方推荐方式. 二.概念理解和知识铺垫 在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上

  • Spring 应用上下文获取 Bean 的常用姿势实例总结

    本文实例讲述了Spring 应用上下文获取 Bean 的常用姿势.分享给大家供大家参考,具体如下: 1. 前言 通常,在Spring应用程序中,当我们使用 @Bean,@Service,@Controller,@Configuration 或者其它特定的注解将 Bean 注入 Spring IoC .然后我们可以使用 Spring 框架提供的 @Autowired 或者 JSR250.JSR330 规范注解来使用由 Spring IoC 管理的 Bean . 2. 从应用程序上下文中获取 Bea

  • 浅谈Spring与SpringMVC父子容器的关系与初始化

    Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean. 了解了Spring与SpringMVC父子容器的关系,接下来让我们看看Spring与SpringMVC容器的初始化过程. 以下讲解使用的web.xml文件如下: <context-param> <param-name>contextConfigLocation</param-name>//指定

  • 详解Spring ApplicationContext加载过程

    1.找准入口,使用ClassPathXmlApplicationContext的构造方法加载配置文件,用于加载classPath下的配置文件 //第一行,执行完成之后就完成了spring配置文件的加载,刷新spring上下文 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext( "classpath:spring-mvc.xml"); //获取实例Bean Person person=con

  • Java Spring 控制反转(IOC)容器详解

    目录 什么是容器? 无侵入容器 IOC控制反转 IOC理论推导 传统应用程序开发的弊端 "注入"机制 小结 IOC本质 DI(依赖注入) 总结 IoC 容器是 Spring 的核心,也可以称为 Spring 容器.Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期. Spring 中使用的对象都由 IoC 容器管理,不需要我们手动使用 new 运算符创建对象.由 IoC 容器管理的对象称为 Spring Bean,Spring Bean 就是

随机推荐