Spring 底层原理与解析 - 容器接口
Spring 底层原理与解析 - 容器接口
BeanFactory 能做哪些事
- BeanFactory 与 ApplicaiotnContext 到底是谁提前做完了对象的加载
在之前的一篇关于 Spring 的文章Spring IoC 与容器的初始化中提到过,BeanFactory 接口与 ApplicationContext 接口之间的关系
可以看到的是 BeanFactory 是 Spring 容器的一个最原始的接口,同时也定义了获取 Bean 对象的方法 getBean() 。
但 BeanFactory 接口所提供的 getBEean() 方法获取 Bean 的加载时机与 ApplicationContext 对象获取的 Bean 对象的 GetBean 是不同的。
我们在上一篇 Spring IoC 与容器的初始化 中已经进行过验证,BeanFactory 初始化 Bean 对象是在执行调用 getBean() 的时候,而 ApplcationContext 是在第一次加载 Spring 的配置文件的时候,就已经将 Bean 对象初始化到了容器当中的。
其实在 ApplicationContext 对象中调用的 getBean() 方式是来自于 BeanFactory 对象的,我们可以从代码中证明这一点。
public class App {public static void main( String[] args ) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");System.out.println("开始执行 getBean 方法");applicationContext.getBean("userService");}
}
public Object getBean(String name) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name);
}
我们进入 applicationContext 对象的 getBean() 方法中可以看到,getBean() 方法其实就是调用了 getBeanFactory() 方法首先获取 BeanFactory 对象,然后调用 BeanFactory 对象的 getBean() 方法获取容器中的 Bean 。
- BeanFactory 能干的事多吗?
BeanFactory 我们前面看到过,该接口所提供的功能似乎很少,唯一用的最多的只要一个 getBean 。那么,我们这么强大的轻量级框架的 Spring 真的就这么”轻“吗?
哎~ 实时不然,我们所用到的绝大多是方法其实都是由 BeanFactory 实现类所提供的,不信你看。
BeanFactory 的一个子接口 ConfiguraableBeanFactory 下的一个实现类 DefaultListableBeanFactory
通过名字就可以看出 ConfiguraableBeanFactory 就是一个可以自己配置的 BeanFactory ,而 DefaultListableBeanFactory 提供了一些默认的 BeanFactory 的方法
可以看到其抽象父类 AbstractAutowireCapableBeanFactory 的继承关系图
我们 F4 进入 SingletonBeanRegistry 的实现类 DefaultSingletonBeanRegistry 中,该实现类中管理了我们在 Spring 容器中创建的所有的对象。
可以看到有一个叫做 singletonObjects 的对象,该对象是一个 HashMap 而这个 Map 集合中就存储这我们 Spring 中创建的所有的 Bean 对象。我们可以通过 DeBug 的方式进行查看,也可以通过反射的方式获取该 singletonObject 中的属性值
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService1" class="com.peggy.service.impl.UserServiceImpl1"/><bean id="userService2" class="com.peggy.service.impl.UserServiceImpl2"/>
</beans>
public class App {public static void main( String[] args ) {
ConfigurableApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
try {
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");singletonObjects.setAccessible(true);ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);/* 通过过滤器只保留一部分 */map.entrySet().stream().filter(e->e.getKey().startsWith("userService")).forEach((e)->{System.out.println(e.getKey()+"="+e.getValue());});} catch (Exception e) {throw new RuntimeException(e);}
}
}
可以看到 singletonObjects 属性中有我们注入的 UserService 对象
ApplicationContext 有哪些扩展的功能
appllicationContext 的主要功能的扩展来自于 MessageSource (国际化处理)、ResourcePatternResolver (资源匹配,来自用磁盘本地的文件资源匹配)、ApplicationEventPublisher (发布事件对象、新用户短信验证注册)、EnvironmentCapable (处理环境信息,环境变量)
- 国际化的处理
@SpringBootApplication
public class SpringDomeApplication {
public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringDomeApplication.class, args);
System.out.println(context.getMessage("hi", null, Locale.CHINA));System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
}
}
- 获取资源
@SpringBootApplication
public class SpringDomeApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringDomeApplication.class, args);/** classpath 到类路径下找到对应的资源* file 到磁盘目录下获取资源* */try {Resource[] resource = context.getResources("application.properties");for (Resource re : resource) {System.out.println(re);}} catch (IOException e) {throw new RuntimeException(e);}}
}
classpath:META-INF/spring.factories* 获取 jar 包下的类路径的所有同名文件
@SpringBootApplication
public class SpringDomeApplication {
public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringDomeApplication.class, args);/** classpath*:META-INF/spring.factories 获取 jar 包下的类路径的所有同名文件* */try {Resource[] resource = context.getResources("classpath*:META-INF/spring.factories");for (Resource re : resource) {System.out.println(re);}} catch (IOException e) {throw new RuntimeException(e);}}
}
- 获取环境变量与信息
@SpringBootApplication
public class SpringDomeApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringDomeApplication.class, args);System.out.println(context.getEnvironment().getProperty("JAVA_HOME"));System.out.println(context.getEnvironment().getProperty("server.port")); }
}
事件的解耦
事件的解耦指的是什么呢?
可以实现这样的一个场景,比如说用户需要进行邮件的发送,用户发送出去一个邮件不需要一直等待,直到接受者接受到邮件后才能做其他的操作。
而我们的事件对象就是就可以达到者一个 发送者
与 接受者
之间相互解耦的目的。
那么,对于我们的发送者来说
可以利用 ApplicationEventPublisher 中提供的 publishEvent 来发送信息,而创建一个监听接受者用户信息的接收。
- 创建一个监听者
/*** @author peggy* @data 2023/2/14 21:47* 事件的接受者*/
@Component
public class ListeningOrage {/*** 注入一个事件的监听器 当接受的监听的对象 执行该方法 * 该方法的参数与方法名返回值都随意* @param registeredEvder*/@EventListenervoid take(UserRegisteredEvder registeredEvder){System.out.println("接受的事件: "+registeredEvder);}
}
- 创建一个时间对象
/*** 事件对象* @author peggy* @data 2023/2/14 21:43*/
public class UserRegisteredEvder extends ApplicationEvent {/*** 事件源* @param source*/public UserRegisteredEvder(Object source) {super(source);}
}
- 事件的发送者
/*** 时间的发送者* @author peggy* @data 2023/2/14 22:00*/
@Component
public class UserSendEvder {@AutowiredApplicationEventPublisher eventPublisher;
/*** 实现的需要调用的时间发送方法* 方法名与方法的参数以及返回值随意*/void send(){System.out.println("发送信息");eventPublisher.publishEvent(new UserRegisteredEvder(this));}
}
- 开始发送事件
@SpringBootApplication
public class SpringDomeApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringDomeApplication.class, args);/** 通过类信息获容器中的发送者的对象,并执行发送者的发送方法* */context.getBean(UserSendEvder.class).send();}
}
这里可以发现我们的接受到的对象就是我们创建的事件发送者的 this 对象本身
相关文章:
Spring 底层原理与解析 - 容器接口
Spring 底层原理与解析 - 容器接口 BeanFactory 能做哪些事 BeanFactory 与 ApplicaiotnContext 到底是谁提前做完了对象的加载 在之前的一篇关于 Spring 的文章Spring IoC 与容器的初始化中提到过,BeanFactory 接口与 ApplicationContext 接口之间的关系 可以看…...
Compose-Navigation简单案例上手
Navigation 快速上手 下面案例简要展示使用 Compose 版本的 Navigation 库来实现两个页面之间的跳转 这是完整的结构(忽略掉红线划过的那个包) 安装适用于 kotlin 的 navigation 依赖 dependencies {implementation("androidx.navigation:navigati…...
855. 考场就座
题目 考场就座 在考场里,一排有 N 个座位,分别编号为 0, 1, 2, …, N-1 。 当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外…...
k8s之ingress(二)
文章目录k8s之ingress1.1、Kubernetes 暴露服务的方式:1.2 基本概念1.3为什么需要Ingress资源1.4 Ingress的工作原理1.5ingress 暴露服务的方式总结k8s之ingress 1.1、Kubernetes 暴露服务的方式: Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、Nod…...
linux下监测串口数据
在编写上下位机通信代码时,需要分阶段测试,确保下位机,线路,上位机都OK. 一.检查设备数据传出 1.确定下位机的串口参数 如果波特率有问题,可能会…...
【面试之闭包】前端面试那些事(2)三分钟深入理解闭包(附详解实例)
目录1、什么是闭包,什么是作用域1.1 变量作用域1.2 闭包是啥?如何改变变量调用格局1.3 闭包的特性2、怎么用闭包,闭包实例应用2.1 常见闭包实例2.2 闭包异步函数的应用2.3 柯里化的应用3、闭包的优缺点3.1 优点3.2 缺点4、片尾彩蛋【写在前面…...
深入浅出带你学习WebSphere中间件漏洞
前言 上一篇文章给大家介绍了中间件glassfish的一些常见漏洞以及利用方法,今天我给大家带来的是WebSphere中间件的常见漏洞以及这些漏洞的利用方法,下面我们首先介绍一下WebSphere中间件是什么,然后展开来讲关于该中间件的漏洞。 WebSphere…...
如何一眼分辨是C还是C++
C语言的历史C语言是由贝尔实验室的Dennis Ritchie在20世纪70年代初开发的一种通用程序设计语言。在早期的计算机时代,许多计算机使用不同的汇编语言编写程序,这导致了程序的可移植性和代码的可重用性很低。因此,Dennis Ritchie在开发C语言时试…...
CMake系列:正确使用多配置编译系统
目录 常见错误 问题现象 正确做法 if指令应该什么时候使用 活学活用 把IF指令用于多配置编译系统是很多初学者容易犯下的错误。这篇文章启示性的教你如何正确理解、使用CMake的多配置编译系统。 常见错误 以Debug和Release配置有不同的宏定义为例,如下所示&a…...
PCB中的HDI板生产中的变化
关键词:HDI概述 HDI发展演变 HDI生产难点如果把一整个电子产业比作浩瀚的宇宙,那些智能电子设备就像宇宙中闪耀的星光,当你以“上帝”的视角手持放大镜去观察时,这些闪烁的星光点点其实都是一个个由精密的“自然规律”所“设计”好…...
程序分析与神经网络后门
原文来自微信公众号“编程语言Lab”:程序分析与神经网络后门 搜索关注“编程语言Lab”公众号(HW-PLLab)获取更多技术内容! 欢迎加入编程语言社区 SIG-程序分析,了解更多程序分析相关的技术内容。 加入方式:…...
redis主从哨兵模式
一.为什么用redis主从模式 1.数据备份:主从复制实现数据的热备份。 2.故障恢复:当主节点出现问题时,由从节点提供服务,实现快速恢复。 3.负载均衡:读写分离,主节点提供写服务,从节点提供读服务。在写少读多时提高Redis的并发。 二.为什么使用哨兵模式 主要用于主节…...
Spring 系列之 MVC
Spring 系列文章目录 文章目录Spring 系列文章目录前言一、介绍二、项目搭建1.创建空项目2.设置maven和lombok3.创建maven web module4. 配置Tomcat启动运行项目(选择local本地)5. 导入jar依赖包6.在web.xml中配置DispatcherServlet7. 加入SpringMVC的配…...
电子技术——分立CS和CE放大器的低频响应
电子技术——分立CS和CE放大器的低频响应 我们之前在学习放大器中从来没有关系过信号频率对放大器的影响,也就是说我们默认放大器具有无限的带宽,这当然不符合现实逻辑。为了说明这一点,我们使用下图: 上图描述了MOS或BJT分立电路…...
代码随想录【Day16】| 104. 二叉树的最大深度、111. 二叉树的最小深度、222. 完全二叉树的节点个数
104. 二叉树的最大深度 题目链接 题目描述: 给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7],…...
状态机图、通信图题
1.下列关于通信图与顺序图中的对象的相同点的叙述.正确的是(D)。A.两种图中都可以表示对象的创建和销毁B.对象在两种图中的位置都没有任何限制C.对象在两种图中的表示方式完全一致D.对象名在两种图中的表示完全一致2.下列关于通信图的说法错误的是(C)。A.通信图是对一次交互过程…...
分布式文件存储Minio学习入门
文章目录一、分布式文件系统应用场景1. Minio介绍Minio优点2. MinIO的基础概念、3. 纠删码ES(Erasure Code)4. 存储形式5. 存储方案二、Docker部署单机Minio三、minio纠删码模式部署四、分布式集群部署分布式存储可靠性常用方法冗余校验分布式Minio优势运行分布式minio使用dock…...
handler解析(4)-Message及Message回收机制
Message中可以携带的信息 Message中可以携带的数据比较丰富,下面对一些常用的数据进行了分析。 /*** 用户定义的消息代码,以便当接受到消息是关于什么的。其中每个Hanler都有自己的命名控件,不用担心会冲突*/ public int what; /*** 如果你…...
Linux使用定时任务监控java进程并拉起
需求描述: 设计一个脚本,通过Linux定时任务,每分钟执行一次,监控jar包进程是否存在,存在则不做动作,不存在则重新拉起jar包程序。 定时任务配置: */1 * * * * bash -x /root/myfile/jars/che…...
Win 10电脑摄像头提示错误代码0xa00f4244怎么办?
如果你的Windows 10电脑无法打开摄像头,提示“我们找不到你的摄像头”的错误消息,错误代码是0xA00F4244,原因可能是杀毒软件阻止了摄像头,或者是摄像头驱动程序有问题。 小编为你整理了摄像头错误代码0xA00F4244的解决方法&#…...
MFC消息机制
1.消息映射消息映射是一个将消息和成员函数相互关联的表。比如,框架窗口接收到一个鼠标左击消息,MFC将搜索该窗口的消息映射,如果存在一个处理WM_LBUTTTONDOWN消息的处理程序,然后就调用OnButtonDown。2.消息映射机制2.1 声明宏 写…...
全国计算机等级考试报名照片要求以及证件照制作教程
马上就全国计算机等级考试就要开始了,相信现在很多同学都在网上进行报名呢,报名的时候肯定需要用到个人证件照片,所以问题来了,我们怎么自己制作证件照片呢?计算机等级考试报名时对证件照都有哪些要求呢?该…...
SQLSERVER 临时表和表变量到底有什么区别?
一:背景 1. 讲故事 今天和大家聊一套面试中经常被问到的高频题,对,就是 临时表 和 表变量 这俩玩意,如果有朋友在面试中回答的不好,可以尝试看下这篇能不能帮你成功迈过。 二:到底有什么区别 1. 前置思…...
技术生态异军突起,昇思MindSpore进入AI框架第一梯队
ChatGPT掀起的新一轮人工智能狂欢下,隐藏在背后的“大模型”正进入越来越多开发者的视野。 诚如几年前开始流行的一种说法:数据是燃料、模型是引擎、算力是加速器。ChatGPT的出现,恰如其分地诠释了数据、模型和算力的“化学反应”。而在其中…...
审批流、工作流、业务流
是业务流、工作流、审批流 业务流:即业务流程,指为了完成某项业务而进行的各种工作的有序组合 工作流:即工作流程,指为了完成某项工作而进行的各种动作的有序组合 审批流:即审批流程,是对某项工作的审批活动…...
如何利用知识库加强内部管理?
许多公司都知道需要有一个面向客户的知识库,以加强客户服务,提供更好的客户体验。 但是很多企业没有意识到的是,拥有一个内部知识库软件对于员工改善沟通和促进知识共享的重要性。 协作是组织成功的关键部分,通过明确的远景和使…...
饕餮 NFT 作品集来袭!
饕餮 NFT 作品集包含 Chili Game 创作的体验《饕餮》第一章中的角色。可以在 The Sandbox 农历新年活动期间(01/18/23 至 02/28/23)体验。 饕餮的故事植根于中国古代神话,主要灵感来自《山海经》,一个关于捉妖人「青蛙侠」的故事。…...
C++中的内存分区、引用、函数
内存分区模型 代码区 存放CPU执行的机器指令代码区是共享的且具有只读性 全局区 全局变量和静态变量都存放在此处全局区还包括了常量区、字符串常量和其他常量也存放在此该区域的数据在程序结束后由操作系统释放const修饰的局部变量并不算在全局区 栈区 由编译器自动分配和释放…...
关于angular表格total模板中一直为0
哈喽 小伙伴们大家好昨天在用angular得antdesign组件得table表格 我用total模板 结果,total一直为0这可是愁坏我了 <ng-template #totalTemplate let-total>找到 {{ total }} 条结果</ng-template>[nzShowTotal]"totalTemplate"最后找到原因了…...
多线程事务怎么回滚
背景介绍1,最近有一个大数据量插入的操作入库的业务场景,需要先做一些其他修改操作,然后在执行插入操作,由于插入数据可能会很多,用到多线程去拆分数据并行处理来提高响应时间,如果有一个线程执行失败&…...
展览设计制作公司/北京百度搜索排名优化
最常用的Eclipse的快捷键,各个实用,由Java攀登网提供。 虽然现在IDEA非常的好用,但是Eclipse还是有一定的受众用户,包括我现在的公司,领导就是让用Eclipse,因此喜欢Eclipse的朋友可以看下。 后面可以再讲…...
wordpress国内最好的主题/网站seo规划
Win7下硬盘安装Ubuntu 12.04 下面本人将介绍适合新手、简单易懂的硬盘安装方法: 1、在Windows7中下载并安装EasyBCD(目前最新版2.1.2) 2、将ubuntu-12.04-desktop-i386.iso文件复制到C盘根目录,用压缩软件打开,再打开c…...
上海网站se0优化/营销类网站
作者 | Tina & Jenny专栏 | 九章算法 到了职业发展的中后期, 程序员多将面临一个艰难的抉择: 是继续从事编程开发走的技术路线, 还是转为管理层面的发展路线? 开发人员的职业发展能否避开向管理层面的转变? 这是一…...
做网站的专业词汇/百度竞价培训班
提问?谁不会?这可能真是一件简单的事,但也未必。我正在看一本书《学会提问》。提问里有大学问。还有一本书,浏览了一遍,书名叫《你的灯亮着吗》。通过网络为人解惑已经有些日子了。近日一些事情让我深深感觉到不少同学…...
想做一个自己设计公司的网站怎么做的/排名优化关键词
在Excel和Word文档中录入信息时,要说F1-F12的快捷键使用,Sara随口而出的肯定是“F4”,毕竟在Excel表格中的“绝对引用”绕不开它呀,O(∩_∩)O哈哈~这不,今天饶有兴趣的来说说这12个快捷键的简单使用,能记一…...
mitao wordpress/seo网络推广是什么意思
---恢复内容开始--- 1.定制标签简介 JSP表示层中需要编写大量的jsp脚本代码 在其他jsp中要重复编写相同的代码,不能做到代码的复用 JSP开发者可以创建新的标签来根据实际需求定制相应的方法----定制标签 使用自定义标签可以实现页面表示层的代码重用 几种常见的标签…...