Spring创建Bean的全过程(一)

2023-11-02

Spring测试环境搭建

​ Spring模块概览,Spring中八大模块,黑色表示该模块的jar包(也就是组件)。例如我们想要使用IOC容器,也就是绿色的CoreContainer,我们需要导入Beans,Core,Context,SpEL(spring-expression)四个包。
在这里插入图片描述

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.13</version>
        </dependency>

resources下面新建beans.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="mysqlImpl" class="com.lv.dao.UserDaoMysqlImpl"/>
    <bean id="oracleImple" class="com.lv.dao.UserDaoOracleImpl"/>
    <bean id="UserServiceImpl" class="com.lv.service.UserServiceImpl">

        <property name="userDao" ref="mysqlImpl"></property>
    </bean>
    <!--
            ref :引用Spring容器中创建好的对象
            value:具体的值,基本数据类型
    -->
</beans>

java下建dao包 分别创建下面几个类

public interface UserDao {
    void getUser();
}

public class UserDaoImpl implements UserDao{

    public void getUser(){
        System.out.println("默认");
    }
}

java下建service包分别创建下面几个类

public interface UserSerivce {
    void getUser();
}


public class UserServiceImpl implements UserSerivce {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUser(){
        userDao.getUser();
    }

}

test目录下建MyTest

// 导包的时候记着导junit
public class MyTest {
    @Test
    public void getUser(){

       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
       userServiceImpl.getUser();
    }
}

1.2容器创建过程

从测试类的ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

进入ClassPathXmlApplicationContext

	/*  
		configLocations: 是xml的名字
		refresh :是否自动刷新上下文、加载所有bean定义和创建所有单例。或者,在进一步配置上下文之后,手动调用REFRESH。
		parent: 父类上下文 也就是父容器
	*/
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		// 保存父容器,并将父容器的环境与当前容器环境合并。
		super(parent);
        // 设置配置文件路径
		setConfigLocations(configLocations);
		if (refresh) {
            // 核心步骤
			refresh();
		}
	}

加载配置文件后,进入AbstractApplicationContext 的refresh()方法,该方法是容器初始化的核心步骤。该方法包含十三个方法:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {  
             // 容器启动的状态
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing
            // 准备刷新,做一些最基本的准备化工作
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            // 获得一个刷新的bean容器,实质就是获取工厂。
            // 加载xml等配置文件,用该文件产生的BeanDefinition来创建一个工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
            // 准备bean工厂
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                // 后置增强 AOP,方便扩展
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
                // 实例化和调用所有 BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 实例化并且注册所有的BeanPostProcessor
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
                // 国际化设置,一般不用
				initMessageSource();

				// Initialize event multicaster for this context.
                // 初始化事件监听多路广播器
				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) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
                // 销毁已经创建的单例避免资源浪费
				destroyBeans();

				// Reset 'active' flag.
                // 重启 active 标记
				cancelRefresh(ex);

				// Propagate exception to caller.
                // 抛出异常
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
                // 重置Spring核心中的常见内核缓存,因为我们可能不再需要单例bean的元数据了
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

接下来我们一个一个看,一个一个具体方法分析:

PrepareRefresh: 准备刷新,做一些基本的准备工作

	/**
	 * Prepare this context for refreshing, setting its startup date and
	 * active flag as well as performing any initialization of property sources.
	 */
	protected void prepareRefresh() {
		// Switch to active.
        // 设置开始事件
		this.startupDate = System.currentTimeMillis();
        // 关闭状态设置为false
		this.closed.set(false);
        // 活跃状态设置为true
		this.active.set(true);
		
        // 日志打印
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
        // 初始化上下文属性资源
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
        // 获取环境  验证上下文需要的属性信息
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
        // 存储预刷新的一些应用信息的监听器
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
            // 将本地应用程序监听器重置为与刷新状态
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
        //  创建一些监听器事件的集合
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

总结:

perpareRefresh()方法

1.设置启动事件

2.设置关闭、活跃的状态

3.初始化属性资源、获取环境信息并验证属性信息

4.设置监听器、重置本地应用的监听器状态以及创建监听事件的集合

重要的点

  • 获取环境信息,验证属性信息 getEnvironment().validateRequiredProperties();
  • 存储预刷新的一些应用信息的监听器,在Spring中是空实现,但是SpringBoot中,是由具体的值的
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring创建Bean的全过程(一) 的相关文章

随机推荐

  • 前端数字显示汉字(字典)

    第一种IF
  • qt delete使用

    在C 中学习过程中 我们都知道 delete 和 new 必须 配对使用 一 一对应 delete少了 则内存泄露 多了麻烦更大 Qt作为C 的库 显然是不会违背C 的前述原则的 可是 在Qt中 我们很多时候都疯狂地用new 却很少用del
  • C语言杨辉三角

    前言 杨辉三角 是二项式系数在三角形中的一种几何排列 在欧洲 这个表叫做帕斯卡三角形 帕斯卡 1623 1662 是在1654年发现这一规律的 比杨辉要迟393年 比贾宪迟600年 杨辉三角是中国古代数学的杰出研究成果之一 它把二项式系数图
  • 05 python 简单猜拳;循环while

    随机数 random 导入randonm库 randint产生一个范围的随机数 import random player int input 输出0 拳 1 剪 2 布 com player random randint 0 2 if pl
  • 使用jspdf生成pdf时,html2canvas循环浏览器卡顿或卡死解决方案:关于这个问题,我的解决方案是不要用html2canvas

    循环卡死当然是有原因的 首先jspdf对canvas也是有最大长度限制的 太长了就转不了 最后还是用wkhtmltopdf这个组件 先将页面上的canvas都转成图片 然后再循环将html字符串传到后台使用wkhtmltopdf这个组件生成
  • linux文件系统命令(6)---touch和mkdir

    一 目的 本文将介绍linux下新建文件或文件夹 删除文件或文件夹命令 touch能够新建文件 mkdir用来新建文件夹 rm用来删除文件或文件夹 本文将选取ubuntu14 04发行版做为描写叙述基础 二 touch命令 linux下新建
  • 关于Python爬虫接单的方法经验分享,实现经济独立

    在现如今这个数据发展的时代中 我想很多人工基本工资只能说是维持自己基本的生活开销的 要是说想要自己家里人生活过得好一些的话 我想很多人是很难这样做到的 我想把我的一些接单经验分享给大家 毕竟来说现在大家的生活都不容易 大家能帮些是一些 能赚
  • vue页面内监听路由变化

    beforeRouteEnter to from next 在渲染该组件的对应路由被 confirm 前调用 不 能 获取组件实例 this 因为当钩子执行前 组件实例还没被创建 beforeRouteUpdate to from next
  • 【ARM】简单移植adb与adbd过程记录

    1 问题 遇到一个比较苛刻的客户 测试程序adb push到开发板时间格式不一样 这都要算软件bug 没办法 只能想办法解决 后续在其他平台验证不会出现时间格式不一致的问题 所以把目标锁定在adbd版本的问题 于是打算重新移植个最新版本的a
  • 【OLED驱动函数详解】

    OLED驱动函数详解 前提 通讯方式 地址排列 寻址方式 正文 初始化 一些使用命令的函数 显示一个字符 在指定位置显示一个字符串 字符串居左显示 字符串居右显示 字符串居中显示 在指定位置显示一个中文字符 在指定区域显示图片 在指定位置显
  • 什么是无线路由器网络协议?

    上一篇我们介绍了什么是网络协议转换器 相信看过的朋友对此都有了一定的认知 可能有些朋友在使用协议转换器的时候用的是无线路由器网络 那么 什么是无线路由器网络协议呢 接下来飞畅科技的小编就来为大家详细介绍下无线路由器网络协议是什么 感兴趣的朋
  • ajax下载文件无响应,xml格式解析不正确

    今天朋友在做文件下载时遇到了一个问题 整个请求后台没有报一点错 而且请求也进入了响应Controller 但是页面就是没有任何响应 让我帮看下文件下载代码是否有问题 所有下载文件代码看了一遍确实没发现任何问题 我百思不得其解 突然想到会不会
  • CentOS7.x 安装RabbitMQ后-自定义配置文件

    承接CentOS7 x 安装RabbitMQ 3 7 x 背景 启动rabbitmq 然后登陆后 可以看到刚刚安装完成的rabbitmq使用的是默认的配置 还没有自定义的配置文件 1 配置文件位置 利用下面的命令查询rabbitmq配置文件
  • SaltStack常用模块

    SaltStack常用模块 SaltStack模块介绍 Module是日常使用SaltStack接触最多的一个组件 其用于管理对象操作 这也是SaltStack通过Push的方式进行管理的入口 比如我们日常简单的执行命令 查看包安装情况 查
  • vue vue-router实现路由拦截功能

    vue vue router实现路由拦截功能 1 目录结构 2 设置路由拦截 路由配置如下 在这里自定义了一个对象的参数meta authRequired true 来标记哪些路由是需要登录验证的 导航被触发的时候只要判断是否目标路由中是否
  • 【AI】Diffusion Models

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 两种思路解决线程服务死循环

    背景 系统突然error飚高 不停Full GC 最后发现是因为调用的外部jar包中方法触发bug导致死循环 不断产生新对象 导致内存大量占用无法释放 最终JVM内存回收机制崩溃 解决思路 服务一旦进入死循环 对应线程一直处于running
  • (已解决)STM32L151使用串口发送数据第一字节为FE问题!

    已解决 STM32L151使用串口发送数据第一字节为FE问题 参考文章 1 已解决 STM32L151使用串口发送数据第一字节为FE问题 2 https www cnblogs com Irvingcode p 11603583 html
  • 【机器学习】KS值

    KS检验 风控角度 分类模型评判指标 KS曲线与KS值 从统计角度 我们知道KS是分析两组数据分布是否相同的检验指标 在金融领域中 我们的y值和预测得到的违约概率刚好是两个分布未知的两个分布 好的信用风控模型一般从准确性 稳定性和可解释性来
  • Spring创建Bean的全过程(一)

    Spring测试环境搭建 Spring模块概览 Spring中八大模块 黑色表示该模块的jar包 也就是组件 例如我们想要使用IOC容器 也就是绿色的CoreContainer 我们需要导入Beans Core Context SpEL s