spring学习-第一讲-beanFactory与ApplicationContext

news2025/1/8 20:00:16

BeanFactory与ApplicationContext区别

创建一个springboot项目,对这个函数的main函数来进行执行。

 ConfigurableApplicationContext context = SpringApplication.run(BeanFactoryApplicationContextStudyApplication.class, args);

很明显,ConfigurableApplicationContext对象就是一个ApplicationContext派生的对象。观察一下这个类所对应的类图。

从这个类图中,我们可以很明确的看出来,BeanFactory与ApplicationContext存在派生关系。

那么,在以前面试的时候,我们都扯皮所说的容器,依赖注入,控制反转之类的。其实,beanFactory便实现了最基本的容器功能,依赖注入,控制反转都是后期扩展的功能。而ApplicationContext是内部持有了beanFactory来完成这个操作的(策略模式),下面看一下源码。

BeanFactory实际上是一个接口,看一下内部的方法。

可以发现,其实核心方法就是getBean来获取到容器内部存放的对象,也就是证明了BeanFactory这个接口的目的确实是作为容器存放对象,以及取出对象的功能。

至于ConfigurableApplicationContext这个类,我们进入源码看一下,发现它本身也是一个interface接口,也就是说,这里其实是多态展示其名下的某一个子类。

在run方法里不断进行跳入,发现最终底层的一个容器对象为AnnotationConfigServletWebServerApplicationContext。看看所包含的类图,目前为止,我这面似乎注意到AbstractApplicationContext这个类。

 

点进来看了下,内部持有了一个ApplicationContext的变量parent对象,意思是存在容器也是存在上下层级的吗?那么ApplicationContext采用策略模式所持有的BeanFactory具体是哪个呢?(接着往后学)。

这里卡住了,回归老师所讲的正题。

BeanFactory功能

照老师所讲,这里底层默认持有的BeanFactory类为DefaultListableBeanFactory,去看一下这个类的类图结构。

 

 结合着这趟的类图结构,我好像理解了BeanFactory与ApplicationContext中的关系了。它这面的结构,可以按照装饰者的类图结构来理解。ApplicationContext与BeanFactory的具体实现类中,最上层都是BeanFactory接口,在下方有两类,一个是具体的BeanFactory实现类。另一个则是创建个ApplicationContext接口来对BeanFactory来进行扩展,在ApplicationContext接口下具体实现ApplicationContext实体类,并且持有BeanFactory实体类来对功能进行扩展。个人类图如下:

目前先按照装饰者的思路来理解,应该是对的。

 

那么DefaultListableBeanFactory上方这么多父层面存在,具体实现了容器功能的是哪个呢?是DefaultSingletonBeanRegistry,看看源码。

如果之前背过面试题循环依赖怎么解决,依赖三级缓存之类的,会对这东西有一定的印象。这俩singleonObjects以及earlySingleonObjects,可不就是一级缓存和二级缓存的存放地吗,这就是容器里要存放的对象的位置。

 我们可以试着拿反射来尝试获取一下内部的元素。看着下面这段代码,我上面画的那个类图就完全理解了。

//在 DefaultSingletonBeanRegistry类中获取到singletonObjects对象
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);

//获取到ApplicationContext中的beanFactory对象,从这里可以看出策略模式持有
 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

//在beanFactory中得到容器内部的所有元素
Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);

//打印最终结果
 map.entrySet().stream().filter(stringObjectEntry -> stringObjectEntry.getKey().equals("messageSource"))
                .forEach(stringObjectEntry -> System.out.println(stringObjectEntry.getKey()+"++++"+stringObjectEntry.getValue()));

注释里写的很明白了,ApplicationContext(最下级类是GenericApplicationContext)中包含一个getBeanFactory方法,我们可以得到其内部持有的beanFactory对象。beanFacotory中的父层面是存在defaultSingleonBeanRegister的,所以它内部的singleObjects也从父层面继承下来,最后获取到了。就是这么个流程。

ApplicationContext功能

从上面我们已经知道了,applicationContext类实质上是在内部依赖了beanFactory对象来完成操作的。那么,除此之外,它还实现了什么额外功能?

回到类图上,我们可以看到,ApplicationContext除了实现BeanFactory系列的接口,还实现了额外的一些接口。分别为MessageSource,ResourcePatternResolver,ApplicationEventPublisher,EnvironmentCapable这四个接口,下面一一介绍一下。

 MessageSource接口

这个接口的功能作用,其实就是我们日常所说的国际化功能。通过在不同配置文件中,配置不同国家的语言,然后在使用过程中来对不同文件中不同语言来进行展示。这块代码整了,但没运行起来,也不算是日常常用的功能,先这么过了。

ResourcePatternResolver接口

ResourcePatternResolver,资源格式解析器,这块其实就是来解析本地资源文件的。如果配置过项目,你是否对一些classpath*:路径,classpath:路径,file:路径这些方式感到眼熟。就像mybatis配置底层的xml访问路径,就是classpath*:路径这种。

classpath:路径1,扫描当前项目下路径1下的所有文件信息。

classpath*:路径2,扫描当前项目下以及底层jar包下的路径2下的所有文件信息

file:路径3,扫描本地磁盘下路径3下的文件信息。

前一段时间看了下网络编程这块吧,书上把这种路径方式称呼为模式:模式特定组成部分。我不确定,网络上的资源路径是否可以通过这种方式来获取呢?后续可以试试,先记一下。

调用方式如下:

 //得到项目路径下的application配置文件(getResource得到的感觉不对,结果感觉还是不对,算了,后续再说)
        Resource[] resource = context.getResources("classpath:application.properties");
        for (Resource resource1 : resource) {
            System.out.println(resource1);
        }

//获取到底层所有starter对应的spring.factories配置文件内信息
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource1 : resources) {
            System.out.println(resource1);
        }

EnvironmentCapable接口

EnvironmentCapable,环境能力。这个功能的作用其实就是从配置文件中,或者环境变量中得到相关的配置信息。调用方式如下:

      //通过EnvironmentCapable来获取到相关的环境变量,这玩意是个接口,我暂时没有找到引用到这个接口的内容
        String java_home = context.getEnvironment().getProperty("java_home");
        String port = context.getEnvironment().getProperty("server.port");
        System.out.println("java_home:"+java_home);
        System.out.println("port:"+port);

ApplicationEventPublisher接口

ApplicationEventPublisher,应用事件发布器,类似发布订阅流程,异步处理的方式。我有一个想法,这个东西,和tomcat内部的listener监听器有没有关系,功能如此像。虽然不了解底层实现,但确实应该是一个东西,有个@EventListener注解。就是个异步处理流程,但假设数量过大的情况下,底层是否用的线程池,怎么实现的,需要好好考虑一下。

写个类试试。

package com.bo.beanfactoryapplicationcontextstudy.one;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Configuration;

import java.time.Clock;

/**
 * @Auther: zeroB
 * @Date: 2023/1/17 16:39
 * @Description: 事件发布器所使用的应用事件对象
 */
public class UserEvent extends ApplicationEvent {

    public UserEvent(Object source) {
        super(source);
    }

    public UserEvent(Object source, Clock clock) {
        super(source, clock);
    }
}

 

package com.bo.beanfactoryapplicationcontextstudy.one;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

/**
 * @Auther: zeroB
 * @Date: 2023/1/17 17:00
 * @Description: 事件发布方
 */
@Component
public class Compment1 {

    @Autowired
    public ApplicationEventPublisher applicationEventPublisher;

    public String name = "落";

    public void register(){
        System.out.println("正在注册");
        //将当前对象发送出去
        applicationEventPublisher.publishEvent(new UserEvent(this));
    }

}
package com.bo.beanfactoryapplicationcontextstudy.one;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * @Auther: zeroB
 * @Date: 2023/1/17 17:00
 * @Description: 事件消费方
 */
@Component
public class Compment2 {

    @EventListener
    public void consume(UserEvent event){
        //接收到信息,并获取到结果
        System.out.println("发布事件已经被消费");
        Compment1 compment1 = (Compment1)event.getSource();
        System.out.println("接收过来的名称信息"+ compment1.name);
    }

}

在启动类中获取的context对象执行如下语句,确实接收到结果了。

   context.getBean(Compment1.class).register();

依赖着容器对象,如果我后续想用这个功能的话,必须获取到容器对象才能做后续的操作。

 

总结

因为初步学习,所以有很多东西其实并不是很了解,需要自身在后面学习的差不多了,然后再继续巩固。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170548.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“互联网+”六年,云徙科技打造数字化经营增长“头牌”

2022年底的全面开放结束了三年疫情&#xff0c;三年来以消费零售为代表的商业领域发生了深刻变局。根据2022年8月的第50次中国互联网络发展状况统计报告&#xff0c;互联网推动网民消费模式变迁&#xff1a;在消费场景方面&#xff0c;从线上消费逐步转变为线上线下融合消费&am…

软件安装教程-Vivado2018.3/ISE14.7/Modelsim10.5/Keil5/AD18/Cadence17.2/CAD2016

硬件工程师软件安装教程 1.Vivado2018.3安装教程 本文的主要内容是介绍 Vivado 2018.3 版本(提取码&#xff1a;ebdx)的安装步骤及其 license(提取码: 6xkh) 的获取与加载。 本文学习自《【ALINX】FPGA ZYNQ视频教程——AX7010/AX7020教程——基础部分》 首先下载安装包&…

【Unity3D】基于模板测试和顶点膨胀的描边方法

1 前言 选中物体描边特效 中介绍了基于模板纹理模糊膨胀的描边方法&#xff0c;该方法实现了软描边&#xff0c;效果较好&#xff0c;但是为了得到模糊纹理&#xff0c;对屏幕像素进行了多次二次渲染&#xff0c;效率欠佳。本文将介绍另一种描边方法&#xff1a;基于模板测试和…

简单使用tomcat查看版本信息等·

Tomcat 是什么 &#xff1f;1.Apache Tomcat 是由 Apache Software Foundation&#xff08;ASF&#xff09;开发的一个开源 Java WEB 应用服务器。2.由于 Tomcat 是由 Java 语言实现的&#xff0c;因此需要运行在 Java 虚拟机上&#xff0c;所以使用前要先安装 JDK&#xff0c;…

JNPF Java3.4.5 .NET6 3.4.5 框架源码 JeeSite快速开发平台

JeeSite JeeSite 快速开发平台的主要目的是能够让初级的研发人员快速的开发出复杂的业务功能&#xff0c;中高级人员有时间做一些更有用的事情。让开发者注重专注业务&#xff0c;其余有平台来封装技术细节&#xff0c;降低技术难度&#xff0c;从而节省人力成本&#xff0c;缩…

电商控价,为什么要找控价公司

刚刚做控价的时候&#xff0c;相信我们心中都有一个疑问&#xff1a;控价嘛&#xff0c;很简单&#xff0c;把标准价格发给低价店铺&#xff0c;让他调价不就行了&#xff1f;不配合&#xff0c;我就投诉&#xff0c;要么我就断货&#xff0c;自己产品自己说了还不算吗&#xf…

《大话数据结构》读书笔记---第一章 数据结构绪论

数据结构&#xff1a;是相互之间存在一种或多种特定关系的数据元素的集合。数据结构是一门研究非数值计算的程序设计问题中的操作对象&#xff0c;以及它们之间关系和操作等相关问题的学科。程序设计数据结构算法数据&#xff1a;是描述客观事物的符号&#xff0c;是计算机中可…

C++复数类——运算符重载和类的传递

复数&#xff1a;我们把形如abi&#xff08;a,b均为实数&#xff09;的数称为复数&#xff0c;其中a称为实部&#xff0c;b称为虚部&#xff0c;i称为虚数单位。当虚部等于零时&#xff0c;这个复数可以视为实数&#xff1b;当z的虚部不等于零时&#xff0c;实部等于零时&#…

【Kotlin】类的继承 ② ( 使用 is 运算符进行类型检测 | 使用 as 运算符进行类型转换 | 智能类型转换 | Any 超类 )

文章目录一、使用 is 运算符进行类型检测二、使用 as 运算符进行类型转换 ( 智能类型转换 )三、Any 超类一、使用 is 运算符进行类型检测 在 Kotlin 中 , 如果不确定一个 实例对象的类型 , 可以 使用 is 运算符进行判定 , 使用方法 实例对象 is 判定类型上述用法可以判定 实例…

Windows11快速入门

1、如何快速上手Win11 Win11官网&#xff1a;https://www.microsoft.com/zh-cn/windows/windows-11?r1 Windows 帮助和学习&#xff1a;https://support.microsoft.com/zh-cn/windows?uizh-CN&rszh-CN&adCN) 2、Win11常用快捷键 2.1、文本编辑快捷键 功能描述快捷键…

【JavaGuide面试总结】MySQL篇·下

【JavaGuide面试总结】MySQL篇下1.介绍一下索引吧2.索引的优缺点3.讲一下索引的底层数据结构Hash 表B 树& B树1.介绍一下索引吧 索引是一种用于快速查询和检索数据的数据结构&#xff0c;其本质可以看成是一种排序好的数据结构。 索引的作用就相当于书的目录。打个比方: …

SpringBoot集成Quartz实现定时任务的动态创建、启动、暂停、恢复、删除

看了好多文章&#xff0c;都只讲了基础的demo用法&#xff0c;也就是简单的创建运行定时任务&#xff0c;对定时任务的管理却很少。 我这里从0开始搭建一个简单的demo&#xff0c;包括定时任务的各种操作&#xff0c;以及API的一些用法&#xff0c;可以实现大多场景的需求。如…

A-Star算法探索和实现(四)

本篇摘要上一篇我们针对障碍物的“死胡同”问题进行了探索&#xff0c;本篇则针对障碍物生成在网格对角顶点处是否有意义以及路径周围存在障碍物时按照对角线移动是否合理两个问题进行探讨&#xff0c;这两个问题主要在于移动规则的限定&#xff0c;主要分为以下两种情况&#…

uniapp富文本内容样式改变处理方式

前言 在日常工作中经常会遇到富文本内容渲染的需求,最常见的问题是页面样式调整好之后,对服务端返回的富文本内容进行渲染时图片显示会有问题,原因在于富文本中的图片信息没有样式处理或是添加样式与父组件中样式不一致.正常显示: 异常显示: 下面就讲一下对于富文本图片样式修…

Jenkins企业邮箱的配置和发送(win版)

在学习jenkins时&#xff0c;我把jenkins安装在自己的笔记本电脑上&#xff0c;以下的配置过程均在win10下进行。 一&#xff1a;安装邮件扩展插件 进入Dashboard——>Manage Jenkins——Manage Plugins——可选插件下选择Email Extension Plugin并“install without rest…

CUDA编程笔记(3)

文章目录前言1.CUDA程序运行时的错误检测检测运行错误的头文件检查运行时的CUDA的api函数检查运行时的CUDA的核函数CUDA-MEMCHECK工具总结前言 CUDA程序运行时的错误检测 1.CUDA程序运行时的错误检测 检测运行错误的头文件 像一些日志文件&#xff0c;一般检测错误都会编写…

浅谈C#多线程 异步编程

背景&#xff1a;线程&#xff08;英语&#xff1a;thread&#xff09;是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流&#xff0c;一个进程中可以并发多个线程&#xff0c;每条线程…

leetcode-11:1814. 统计一个数组中好对子的数目

原题为&#xff1a; 给你一个数组 nums &#xff0c;数组中只包含非负整数。定义 rev(x) 的值为将整数 x 各个数字位反转得到的结果。比方说 rev(123) 321 &#xff0c; rev(120) 21 。我们称满足下面条件的下标对 (i, j) 是 好的 &#xff1a; 0 < i < j < nums.l…

由浅入深使用validation框架进行参数校验

1 引言 平时在业务开发过程中 controller 层的参数校验有时会存在下面这样的判断 public String add(UserVO userVO) {if(userVO.getAge() null){return "年龄不能为空";}if(userVO.getAge() > 120){return "年龄不能超过120";}if(userVO.getName().is…

Mysql安全之权限用户管理参考手册

一、背景 日常Mysql维护过程中&#xff0c;基于安全要求和规定&#xff0c;需要对Mysql进行分权&#xff0c;接入金库、账户密码满足16位复杂度&#xff0c;对特定表授权&#xff0c;只读用户&#xff0c;最小化权限等处理&#xff1b;本文简要梳理下常用命令操作&#xff0c;…