【Spring高级】第1讲:BeanFactory 与 ApplicationContext

news2024/12/25 2:37:23

目录

    • 两者关系
    • BeanFactory功能
    • ApplicationContext功能

两者关系

BeanFactoryApplicationContext都是Spring框架中非常重要的接口,它们都与Spring的IoC容器有关。

下面通过SpringApplication的引导类来说明上面两个接口。

看下面代码:

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
    }
    
}

上面代码中,通过调用SpringApplication.run()方法,返回的就是Spring的容器,也就是代码中的ConfigurableApplicationContext类型,他继承了ApplicationContext,是它的子接口。

下面可以看下类图:

在这里插入图片描述

可以看到ConfigurableApplicationContext继承了很多的接口,其中上层之一就有ApplicationContextApplicationContext又继承了很多其他接口,最顶层的之一就是BeanFactory

结论:ApplicationContext间接继承了BeanFactory,它在BeanFactory基础上又提供了很多功能扩展。

进入context的getBean方法,其实调用了父类AbstractApplicationContextgetBean方法,如下:

@Override
public Object getBean(String name) throws BeansException {
   assertBeanFactoryActive();
   return getBeanFactory().getBean(name);
}

可以看到,其实容器的getBean方法就是间接调用了beanFactorygetBean方法。

debug查看context的属性,如下:

在这里插入图片描述

可以看到容器context会有个beanFactory属性。另外,展开beanFactory属性,可以看到还有个singletonObjects属性,它就是用来存储容器中的单例Bean的一个Map集合。

总结:

BeanFactory是Spring框架中最底层的接口,是IoC最核心的接口。它定义了IoC的基本功能,其中最核心的是getBean方法,来获取Bean。控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供。

ApplicationContextBeanFactory的子接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,如国际化、事件传播、资源加载等。还提供了bean的实例缓存、生命周期管理、bean的实例代理、bean的发布等高级服务。

BeanFactory功能

BeanFactory本身的功能很简单,其源码如下:

public interface BeanFactory {

   /**
    * FACTORY_BEAN前缀
    */
   String FACTORY_BEAN_PREFIX = "&";


   /**
    * 根据名字获取bean
    */
   Object getBean(String name) throws BeansException;

   /**
    * 根据名称和类型获取bean
    */
   <T> T getBean(String name, Class<T> requiredType) throws BeansException;

   /**
    * 根据名字和构造参数或工厂方法参数获取bean
    */
   Object getBean(String name, Object... args) throws BeansException;

   /**
    * 根据类型获取bean
    */
   <T> T getBean(Class<T> requiredType) throws BeansException;

   /**
    * 根据类型和构造参数或工厂方法参数获取bean
    */
   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

   /**
    * 特定bean的提供者
    */
   <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

   /**
    * 特定bean的提供者
    */
   <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

   /**
    * 是否含有bean
    */
   boolean containsBean(String name);

   /**
    * 是否单例
    */
   boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

   /**
    * 
    */
   boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

   /**
    * 是否原型
    */
   boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

   /**
    * 检查执行name的bean是否是指定类型
    */
   boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

   /**
    * 获取bean的类型
    */
   @Nullable
   Class<?> getType(String name) throws NoSuchBeanDefinitionException;

   /**
    * 获取bean的类型
    */
   @Nullable
   Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

   /**
    * 获取bean的别名
    */
   String[] getAliases(String name);

}

主要有以下几个功能:

  • getBean:获取bean
  • containsBean:是否含有bean
  • getType:bean的类型

除了以上基本功能,它还有大量的实现类,提供了其他丰富的功能,例如DefaultListableBeanFactory,其类图如下

在这里插入图片描述

可以看到,它继承了AbstractAutowireCapableBeanFactory,顶层继承了BeanFactory。实现了其他丰富的功能。

他存储着容器的所有的单例bean,其功能实现是在父类DefaultSingletonBeanRegistry中,有个属性为singletonObjects

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

存储着所有单例bean的名称和bean的map。

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
//        context.getBean("aaa");

        // 获取
        Field singletonObjectsField = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjectsField.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String, Object> singletonObjects = (Map<String, Object>) singletonObjectsField.get(beanFactory);
        System.out.println(singletonObjects);
    }

}

ApplicationContext功能

回顾下ApplicationContext的类图:

在这里插入图片描述

上图中,ApplicationContext区别于BeanFactory的主要功能就是基于以下4个接口:

  • EnvironmentCapable:用于访问应用程序环境属性的接口,这些属性可能来自不同的源,如属性文件、系统属性、命令行参数等。
  • ApplicationEventPublisher:用于发布应用程序事件。当应用程序中的某些事情发生时(例如,一个bean被创建或一个特定的操作被执行),您可以发布一个事件,然后任何对该事件感兴趣的监听器都可以接收到通知并执行相应的操作。这是观察者模式的一个实现,允许组件之间进行解耦的通信。
  • ResourcePatternResolver:解析资源路径,并可能支持使用通配符来匹配多个资源。它通常用于加载配置文件、图片、模板等资源。
  • MessageSource:用于国际化(i18n)和本地化(l10n)的消息解析,提供程序的多语言支持。

下面一一演示。

  1. 国际化

国际化文件均在 src/resources 目录下

messages.properties(空)

messages_en.properties

hi=Hello

messages_ja.properties

hi=こんにちは

messages_zh.properties

hi=你好

注意

  • ApplicationContext 中 MessageSource bean 的名字固定为 messageSource
  • 使用 SpringBoot 时,国际化文件名固定为 messages
  • 空的 messages.properties 也必须存在

示例代码:

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
//        context.getBean("aaa");

        // 国际化
        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.CHINESE));
        System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
    }

}

结果如下:

Hello
你好
こんにちは
  1. 获取资源

示例:

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
//        context.getBean("aaa");

        // 获取资源
      	// 注意classpath后的路径如果是jar包里,需要加冒号
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }
    }
}

结果如下:

URL [jar:file:/Users/fltech/.m2/repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar!/META-INF/spring.factories]
URL [jar:file:/Users/fltech/.m2/repository/org/springframework/spring-beans/5.3.23/spring-beans-5.3.23.jar!/META-INF/spring.factories]
URL [jar:file:/Users/fltech/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.13/spring-boot-autoconfigure-2.6.13.jar!/META-INF/spring.factories]
  1. 获取环境属性

增加配置文件 application.properties,如下:

server.port=8080
logging.level.com.cys=debug

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=123456

server.servlet.session.timeout=30m

示例代码:

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
//        context.getBean("aaa");

        // 获取环境属性
        System.out.println(context.getEnvironment().getProperty("java.home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));
    }
}

既可以拿到系统级的环境变量,也可以拿到配置文件里的配置,结果如下:

/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home
8080
  1. 事件发布订阅

事件发布订阅需要事件和监听器两个角色。

首先需要自定义一个事件,继承接口ApplicationEvent

import org.springframework.context.ApplicationEvent;

public class DemoEvent extends ApplicationEvent {
    public DemoEvent(Object source) {
        super(source);
    }
}

定义一个监听器:

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

@Component
public class DemoListener {

    /**
     * 使用EventListener注解来监听
     *
     * @param event 注意参数要与事件的类型相同
     */
    @EventListener
    public void doListener(DemoEvent event) {
        System.out.println("监听到消息...");
    }

}

启用监听:

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
//        context.getBean("aaa");

        // 事件发布
        context.publishEvent(new DemoEvent(context));
    }
}

启动后成功监听到消息。

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

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

相关文章

【场景题】如何设计一个购物车功能?

本文参考文章&#xff1a;https://www.hollischuang.com/archives/6998 https://www.woshipm.com/pd/4115447.html https://zq99299.github.io/note-book/back-end-storage/01/03.html 首先我们要明白&#xff1a;购物车系统在电商系统中的角色是作为用户选购商品和最终下单的桥…

Flutter中的三棵树

Widget Tree&#xff1a; 页面配置信息。 Element Tree&#xff1a; Widget tree的实例化对象&#xff0c;创建出renderObject&#xff0c;并关联到element.renderobject属性上&#xff0c;最后完成RenderObject Tree的创建。 RenderObject Tree&#xff1a;完成布局和图层绘制…

Unity2013.1.19_DOTS_Burst compiler

Unity2013.1.19_DOTS_Burst compiler DOTS是一种新产品&#xff0c;现在尚在起步阶段。由于它处于持续发展中&#xff0c;随着我们努力使其达到最佳状态&#xff0c;您将看到API会不断演变和日趋成熟。 DOTS包含以下元素&#xff1a; 实体组件系统(ECS) - 提供使用面向数据的…

有个朋友被骗了,大家要擦亮眼睛

1.引言 大家好&#xff0c;我是Leo哥&#x1fae3;&#x1fae3;&#x1fae3;&#xff0c;昨天凌晨有个粉丝朋友找到Leo哥&#xff0c;咨询一些问题&#xff0c;现在的朋友们真卷呐&#xff0c;大半夜还在挑灯夜战。可无奈Leo哥12点之前已经睡了&#xff0c;身体为重&#xf…

云服务器2核4G能支持多少人同时访问?2核4G5M并发量评测

腾讯云轻量应用服务器2核4G5M配置一年优惠价165元、252元15个月、三年756元&#xff0c;100%CPU性能&#xff0c;5M带宽下载速度640KB/秒&#xff0c;60GB SSD系统盘&#xff0c;月流量500GB&#xff0c;折合每天16.6GB流量&#xff0c;超出月流量包的流量按照0.8元每GB的价格支…

安装ProxySQL,教程及安装链接(网盘自提)

一、网盘下载&#xff0c;本地直传 我网盘分享的是proxysql-2.5.5-1-centos8.x86_64.rpm&#xff0c;yum或者dnf直接安装就行 提取码&#xff1a;rhelhttps://pan.baidu.com/s/1nmx8-h8JEhrxQE3jsB7YQw 官方安装地址 官网下载地址https://repo.proxysql.com/ProxySQL/ 二、…

[项目设计] 从零实现的高并发内存池(三)

&#x1f308; 博客个人主页&#xff1a;Chris在Coding &#x1f3a5; 本文所属专栏&#xff1a;[高并发内存池] ❤️ 前置学习专栏&#xff1a;[Linux学习] ⏰ 我们仍在旅途 ​ 目录 4.CentralCache实现 4.1 CentralCache整体架构 4.2 围绕Span的相关设计…

从0到1入门C++编程——09 STL、string容器、vector容器、deque容器

文章目录 一、标准模板库STL二、容器算法迭代器应用1、遍历容器中整型数据2、遍历容器中自定义数据类型3、容器中嵌套容器 三、string容器1、构造函数2、赋值操作3、字符串拼接4、查找和替换5、字符串比较6、字符访问与存取7、插入和删除8、子串 四、vector容器1、构造函数2、赋…

灯丝灯双通道低过温高压线性恒流芯片SM2082ED的应用及特性解析

双通道低过温高压线性恒流芯片是一种电子芯片&#xff0c;它具有双通道设计&#xff0c;可以在高电压条件下工作&#xff0c;并具有低过温特性。这种芯片通常用于需要高电流和高电压的应用&#xff0c;如LED照明、激光器、电机驱动等。 双通道设计意味着该芯片可以同时处理两个…

高级软件开发知识点

流程 算法题简历上项目用到技术、流程、遇到问题HR 准备 常考的题型和回答思路刷100算法题&#xff0c;理解其思想&#xff0c;不要死记最近一家公司所负责的业务和项目&#xff1a; 项目背景、演进之路&#xff0c;有哪个阶段&#xff0c;每个阶段主要做什么项目中技术选型…

【Sql Server】C#通过拼接代码的方式组合添加sql语句,会出现那些情况,参数化的作用

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

想要高薪还想要低要求?想转行做Python自动化测试,我该怎么做?

前言 最近小编连续收到好几个粉丝的私信询问&#xff1a;我年纪上来了&#xff0c;原来的行业做不下去了&#xff0c;想转行还能行吗&#xff1f;我是女生&#xff0c;计算机专业快毕业了&#xff0c;但是不喜欢做开发怎么办&#xff1f;我对编程行业感兴趣&#xff0c;想学编…

社交媒体的未来图景:探索Facebook的数字化之旅

社交媒体已经成为现代社会不可或缺的一部分&#xff0c;其影响力已经深入到人们生活的方方面面。而在众多社交媒体平台中&#xff0c;Facebook无疑是其中的巨头&#xff0c;其数字化之旅更是引领着整个社交媒体行业的发展方向。本文将深入探讨社交媒体的未来图景&#xff0c;以…

Linux中服务端开发

1 创建socket,返回一个文件描述符lfd---socket(); 2 将lfd和IP&#xff0c;PROT进行绑定---bind(); 3 将lfd由主动变成被动监听---listen(); 4 接收一个新的连接&#xff0c;得到一个的文件描述符cfd--accept() --该文件描述符用于与客户端通信 5 while(1) { 接受数据&a…

证明高维度神经网络模型是低纬度神经网络模型的加和

神经网络中矩阵乘法的分解与应用 启发标题&#xff1a;神经网络中矩阵乘法的分解与应用摘要&#xff1a;引言&#xff1a;方法&#xff1a;实验&#xff1a;结论&#xff1a;参考文献&#xff1a;附录1附录2实验数据 启发 理论上 更具矩阵乘法 A[p,mn]B[mn,q]C[p,q] Acat(A[:,…

ChatGPT 4.0 升级指南

1.ChatGPT 是什么&#xff1f; ChatGPT 是由 OpenAI 开发的一种基于人工智能的聊天机器人&#xff0c;它基于强大的语言处理模型 GPT&#xff08;Generative Pre-trained Transformer&#xff09;构建。它能够理解人类语言&#xff0c;可以为我们解决实际的问题。 1.模型规模…

K8S实现零宕机实践

越来越多的大厂都在上云、上容器、上K8S编排&#xff0c;K8S和容器云确实帮助我们解决了很多问题。但是&#xff0c;带来方便的同时&#xff0c;也让我们的架构变得更复杂了&#xff0c;更难于依靠“老经验”来解决问题了。虽然我们不用再费力考虑一层的问题&#xff0c;怎么实…

《低代码平台开发实践:基于React》读书心得与实战体验

低代码平台开发实践标题 &#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 一、引…

【EI会议征稿通知】第七届交通运输与土木建筑国际学术论坛(ISTTCA 2024)

第七届交通运输与土木建筑国际学术论坛&#xff08;ISTTCA 2024&#xff09; 2024 7th International Symposium on Traffic Transportation and Civil Architecture 交通运输是经济发展的先行官&#xff0c;而岩土是发展交通运输网络无法避开的话题。将传统的土木工程技术与先…

Linux 设置快捷命令

以ll命令为例&#xff1a; 在 Linux 系统上&#xff0c;ll 命令通常不是一个独立的程序&#xff0c;而是 ls 命令的一个别名。 这个别名通常在用户的 shell 配置文件中定义&#xff0c;比如 .bashrc 或 .bash_aliases 文件中。 要在 Debian 上启用 ll 命令&#xff0c;你可以按…