IOC原理之IoC容器的初始化过程

el/2024/2/26 0:23:21

IoC容器的初始化过程包括Resource定位BeanDefinition的载入以及向IoC容器注册这些BeanDefinition三个阶段。

IoC容器的初始化过程概要

IoC容器的初始化包括三个过程:

  • 第一个过程是 Resource定位 过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口。比如.在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象。在类路径中的Bean定义信息可以使用ClassPathResource来进行抽象等等。这个定位过程类似于容器寻找数据的过程,就像用水捅装水先要把水找到一样。

  • 第二个过程是 BeanDefinition的载入 。这个载入过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。下面介绍这个数据结构的详细定义。具体来说,这个BeanDefinition实际上就是POJO对象在IoC容器中的抽象。通过这个BeanDefinition定义的数据结构,使IoC容器能够方便地对Polo对象也就是Bean进行管理。

  • 第三个过程是 向IoC容器注册这些Bean Definition 的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程把载人过程中解析得到的BeanDeftnition向IoC容器进行注册。在IoC容器内部将BeanDefinition注人到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的

几个常用的ApplicationContext

1. FileSystemXmlApplicationContext

FileSystemXmlApplicationContext的继承体系:

由继承关系可知,FileSystemXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader

看看其完整继承体系:

2. ClassPathXmlApplicationContext

ClassPathXmlApplicationContext的继承体系:

由继承关系可知,ClassPathXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader。和上面的FileSystemXmlApplicationContext如出一辙。

看看其完整继承体系:

3. AnnotationConfigApplicationContext

AnnotationConfigApplicationContext的继承体系:

可以看到,AnnotationConfigApplicationContext,也是通过DefaultResourceLoader读取Resource

看看其完整继承体系:

详细分析IoC初始化过程

以常用的ClassPathXmlApplicationContext为例:

1、 新建resources/META-INF/spring/context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.source.IoC.domain.User"><property name="name" value="张三"/></bean></beans>

2、 新建User

public class User {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

3、

public static void main(String args[]) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();applicationContext.setConfigLocation("classpath:/META-INF/spring/context.xml");applicationContext.refresh();User user = applicationContext.getBean("user", User.class);System.out.printf("user.getName() = %s \n", user.getName());}

运行main方法,整个运行过程如下:

所以这里主要要来看一看AbstractApplicationContext中的refresh() 这个函数:

 public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {this.prepareRefresh();//这里是在子类中启动refreshBeanFactory()定位并载入ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//prepare the bean factory for use in this contextthis.prepareBeanFactory(beanFactory);try {//设置BeanFactory的后置处理this.postProcessBeanFactory(beanFactory);//调用BeanFactory的后处理器,这些后处理器是在Bean定义中想容器注册的this.invokeBeanFactoryPostProcessors(beanFactory);//注册Bean后处理器,在Bean创建过程中调用this.registerBeanPostProcessors(beanFactory);//对上下文中的消息源进行初始化this.initMessageSource();//初始化上下文中的事件机制this.initApplicationEventMulticaster();//初始化其他的特殊Beanthis.onRefresh();//检查监听Bean并且将这些Bean向容器注册this.registerListeners();//实例化所有的(non-lazy-init)单件this.finishBeanFactoryInitialization(beanFactory);//发布容器事件,结束Refresh过程this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}//为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件Beanthis.destroyBeans();//重置'active'标志this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

这个obtainFreshBeanFactory很关键,这里面有 IoC的Resource定位和载入

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//资源定位和载入,是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法this.refreshBeanFactory();//getBeanFactory是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();if (this.logger.isDebugEnabled()) {this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);}return beanFactory;}

看看refreshBeanFactory()源码如下:

   protected final void refreshBeanFactory() throws BeansException {//这里判断,如果建立了BeanFactory,则销毁并关闭该BeanFactoryif (this.hasBeanFactory()) {this.destroyBeans();this.closeBeanFactory();}try {//这里的创建并设置持有的DefaultListableBeanFactor的地方DefaultListableBeanFactory beanFactory = this.createBeanFactory();beanFactory.setSerializationId(this.getId());this.customizeBeanFactory(beanFactory);//载入Bean ,抽象方法,委托子类AbstractXmlApplicationContext实现this.loadBeanDefinitions(beanFactory);Object var2 = this.beanFactoryMonitor;synchronized(this.beanFactoryMonitor) {this.beanFactory = beanFactory;}} catch (IOException var5) {throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);}}

看看子类AbstractXmlApplicationContext中实现的loadBeanDefinitions

 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = this.getConfigResources(); //只可能为nullif (configResources != null) { //不会走这一条路 参数类型Resource...reader.loadBeanDefinitions(configResources);}String[] configLocations = this.getConfigLocations();if (configLocations != null) { // 参数类型String... reader.loadBeanDefinitions(configLocations);}}@Nullableprotected Resource[] getConfigResources() {return null;}

继续往下看AbstractBeanDefinitionReader流操作类的loadBeanDefinitions,这里的流操作来实现IoC的载入

     public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;String[] var3 = locations;int var4 = locations.length;for(int var5 = 0; var5 < var4; ++var5) {String location = var3[var5];counter += this.loadBeanDefinitions(location); //调用下面的函数}return counter;}public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return this.loadBeanDefinitions(location, (Set)null); //调用下面的函数}public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = this.getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");} else {int loadCount;if (!(resourceLoader instanceof ResourcePatternResolver)) {Resource resource = resourceLoader.getResource(location);loadCount = this.loadBeanDefinitions((Resource)resource);if (actualResources != null) {actualResources.add(resource);}if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;} else {try {Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);loadCount = this.loadBeanDefinitions(resources);if (actualResources != null) {Resource[] var6 = resources;int var7 = resources.length;for(int var8 = 0; var8 < var7; ++var8) {Resource resource = var6[var8];actualResources.add(resource);}}if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;} catch (IOException var10) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);}}}}

loadBeanDefinitions会调用DefaultResourceLoader中的getResource

public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");Iterator var2 = this.protocolResolvers.iterator();Resource resource;do {if (!var2.hasNext()) {if (location.startsWith("/")) {return this.getResourceByPath(location);}if (location.startsWith("classpath:")) {return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());}try {URL url = new URL(location);return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));} catch (MalformedURLException var5) {return this.getResourceByPath(location);}}ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();resource = protocolResolver.resolve(location, this);} while(resource == null);return resource;}

可以看到,getResource又调用了子类实现的getResourceByPath方法或是子类传递过来的字符串,实现 Resource定位

整个过程就说得通了。总结起来就是,Resource资源通过最外层的实现类传进来的字符串或者直接调用getResourceByPath方法,来获取bean资源路径,然后通过AbstractBeanDefinitionReader流操作实现载入,最后通过AbstractApplicationContextregisterListeners 进行注册。这就是IoC容器的初始化过程。

其他容器的初始化过程,由上面的继承关系对比,就可以知道是差不多的,这里就不一个一个分析了。


http://www.ngui.cc/el/4466049.html

相关文章

Spring AOP原理之建立AopProxy代理对象

在Spring AOP实现中&#xff0c;使用的核心技术是动态代理&#xff0c;而这种动态代理实际上是JDK的一个特性(在JDK 1.3以上的版本里&#xff0c;实现了动态代理模式)。通过JDK的动态代理特性&#xff0c;可以为任意Java对象创建代理对象&#xff0c;对于具体使用来说&#xff…

Spring AOP原理之拦截器调用的实现

接上文 Spring AOP原理之建立AopProxy代理对象 在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候&#xff0c;相关的拦截器已经配置到代理对象中去了&#xff0c;拦截器在代理对象中起作用是通过对这些方法的回调来完成的。如果使用JDK的Proxy来生成代理对象&…

Spring MVC原理之Spring应用上下文(IoC容器)在Web容器中的启动分析

Spring IoC是一个独立的模块&#xff0c;它并不是直接在Web容器中发挥作用的。如果要在Web环境中使用IoC容器&#xff0c;需要Spring为IoC设计一个启动过程&#xff0c;把IoC容器导人&#xff0c;并在Web容器中建立起来。具体说来&#xff0c;这个启动过程是和Web容器的启动过程…

Spring MVC原理之Spring MVC的设计与实现

接上文 SpringMVC原理之Spring应用上下文&#xff08;Ioc容器&#xff09;在Web容器中的启动分析。 在前文的分析过程中&#xff0c;了解了 Spring的上下文体系通过ContextLoader和DispatcherServiet建立并初始化的过程。在完成对ContextLoaderListener的初始化以后&#xff0c…

Spring JDBC的设计与实现

设计原理 在Spring JDBC中&#xff0c;JdbcTemplate 是一个主要的模板类&#xff0c;它的类继承关系如图&#xff1a; 从类继承关系上来看&#xff0c;JdbcTemplate继承了基类JdbcAccessor和接口类JdbcOperation。在基类JdbcAccessor的设计中&#xff0c;对DataSource数据源…

Spring事务处理浅析

类层次结构 在Spring的事务处理模块中.可以看到的类层次结构如图&#xff1a; 可以看到&#xff0c;Spring事务处理模块是通过AOP功能来实现声明式事务处理的&#xff0c;比如事务属性的配置和读取&#xff0c;事务对象的抽象等。因此&#xff0c;在Spring事务处理中&#xff…

dubbo管理控制台dubbo-admin安装

资源&#xff1a; dubbo源码 和 中文文档 下载源码 下载dubbo-admin模块代码&#xff0c;这个还真不太好找&#xff0c;可能是因为dubbo迁移至Apache 维护后&#xff0c;代码还没迁移好&#xff1f;&#xff1f;&#xff1f; 我是在 https://github.com/apache/incubator-du…

React Native 项目环境配置、调试以及打包

去年在做React Native混合开发的时候&#xff0c;写过几篇笔记&#xff1a; react-native对android物理返回键back的监听以及基类封装 react native导航navigator react-native 与安卓端通信 android 端集成react native Fetch 网络请求简单封装&#xff0c;支持超时入口 …

Rest 概要

REST RESTful Representational State Transfer。是在因特网上提供计算机系统之间的互操作性的一种方式。基于Http协议的资源传递&#xff0c;包括JSON、XML和文本等。 统一接口 资源识别&#xff08;Identification of resources&#xff09; URI&#xff08;Uniform Resou…

构建一个REST风格的Web服务

你需要什么 大约15分钟IntelliJ IDEA或其他编辑器JDK 1.8或更高版本Maven 3.2 你会建立什么 您将在以下地址构建一个将接受HTTP GET请求的服务&#xff1a; http://localhost:8080/greeting 会返回一个JSON 格式的数据&#xff1a; {"id":1,"content"…