当前位置: 首页 > news >正文

深度理解spring——BeanFactory的实现

BeanFactory

  • Spring之BeanFactory
    • 什么是BeanFactory
    • ApplicationContext相对BeanFactory实现的功能性扩展
      • 1. MessageSource
      • 2. ResourcePatternResolver
      • 3. ApplicationEventPublisher
      • 4. EnvironmentCapable
      • 通用ApplicationContext实践实现BeanFactory
      • BeanFactory后处理器排序让谁优先执行
      • 第一种实现通过xml等方式实现的bean注入原理
        • 第二种基于磁盘路径下 xml 格式的配置文件来创建
        • 第三种较为经典的容器,基于java配置类来创建
        • 第四种较为经典的容器,基于java配置类来创建,并且还可以用于web环境

Spring之BeanFactory

什么是BeanFactory

BeanFactory是SpringApplication类的父类接口
BeanFactory才是Spring的核心容器,主要的SpringApplication类都组合了他的功能。
通过Ctrl+alt+u可以看到
在这里插入图片描述
可以从图片中看到SpringApplication是继承了BeanFactory接口对BeanFactory进行了功能性的扩展。
比如SpringApplication获取一个bean的对象

       run.getBean(BreadRollMallServer.class);

他实际上是通过组合了BeanFactory实现找个获取对象的功能,可以看出来SpringApplication是间接的调用了BeanFactory的功能
在这里插入图片描述

ApplicationContext相对BeanFactory实现的功能性扩展

在这里插入图片描述

1. MessageSource

MessageSource 是 Spring 框架里用于消息解析与国际化的核心接口。借助它,你能够依据不同的语言环境获取对应的文本消息,从而实现国际化支持。像错误消息、提示信息这类文本内容,就可以通过 MessageSource 进行管理。

2. ResourcePatternResolver

ResourcePatternResolver 接口可用来解析资源路径,并且支持使用通配符来匹配多个资源。它是 ResourceLoader 的扩展,能够依据给定的资源路径模式查找多个资源。在加载配置文件、静态资源等场景中会经常用到。

3. ApplicationEventPublisher

ApplicationEventPublisher 接口提供了发布应用事件的功能。在 Spring 应用里,事件机制是一种重要的设计模式,允许组件之间以松耦合的方式进行通信。通过 ApplicationEventPublisher,你可以发布自定义的应用事件,其他组件可以监听这些事件并做出响应。

应用场景:用户注册时候的发短信发邮件。

4. EnvironmentCapable

EnvironmentCapable 接口表明一个对象具备获取 Environment 对象的能力。Environment 对象封装了应用程序运行时的环境信息,包含系统属性、环境变量、配置文件属性等。借助 Environment,你可以方便地获取和管理这些属性。

通用ApplicationContext实践实现BeanFactory

public class TestBeanFactory {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// bean 的定义(class(类型), scope(单例or多例), 初始化方法, 销毁方法)// BeanDefinitionBuilder..xxx.xxx.xxx.getBeanDefinition()AbstractBeanDefinition beanDefinition =BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();//(beanName,xxx)将bean注册到bean工厂中beanFactory.registerBeanDefinition("config", beanDefinition);// 【重点】给 BeanFactory 添加一些常用的后处理器(对BeanFactory的扩展) //将后处理添加到bean工厂AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);// BeanFactory 后处理器主要功能,补充了一些 bean 定义// beanFactory.getBeansOfType 根据类型获取多个bean//BeanFactoryPostProcessor.class拿到bean工厂的所有后处理器,对bean工厂做出扩展就可以解析@bean注解等。beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {//拿到bean工厂的所有后处理器并且执行beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);//执行BeanFactory后置处理器});// 添加 BeanPostProcessor  也就是添加bean的后处理器//bean后处理器 针对bean的生命周期各个阶段进行扩展,例如@Autowire @ResousebeanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}}static class Bean1 {private static final Logger log = LoggerFactory.getLogger(Bean1.class);@Autowiredprivate Bean2 bean2;}static class Bean2 {private static final Logger log = LoggerFactory.getLogger(Bean2.class);}
}

通过这个案例,你可以看到如何使用 DefaultListableBeanFactory 创建和管理 Bean,以及如何使用后置处理器在 Bean 的生命周期中执行自定义逻辑。
区别对比

  1. 作用时机
    BeanFactoryPostProcessor:在 BeanFactory 完成 Bean 定义的加载之后,但在 Bean 实例化之前执行。也就是说,它处理的是 Bean 的定义信息,而不是 Bean 实例。
    BeanPostProcessor:在 Bean 实例化之后,初始化前后执行。它作用于已经创建好的 Bean 实例。
  2. 作用对象
    BeanFactoryPostProcessor:作用于 BeanFactory 本身,主要用于修改 BeanFactory 中 Bean 的定义信息,例如修改 Bean 的属性值、作用域等。
    BeanPostProcessor:作用于具体的 Bean 实例,允许开发者在 Bean 初始化前后对其进行定制化处理。
  3. 功能侧重点
    BeanFactoryPostProcessor:侧重于对 Bean 定义的全局修改和扩展,例如动态添加或修改 Bean 定义,调整 Bean 的配置等。
    BeanPostProcessor:侧重于对 Bean 实例的个性化处理,例如对 Bean 进行增强、验证、日志记录等。

总结:
1.bean工厂不会主动调用beanFactory后处理器
2.bean不会主动添加后处理器
3.不会主动初始化单例
4.不会解析BeanFactory

BeanFactory后处理器排序让谁优先执行

在这里插入图片描述

第一种实现通过xml等方式实现的bean注入原理

通过xml注入bean容器

  // ⬇️1.最为经典的容器,基于classpath 下 xml 格式的配置文件来创建public void testClassPathXmlApplicationContext() {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_bean.xml");for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
第二种基于磁盘路径下 xml 格式的配置文件来创建
        //基于磁盘路径下 xml 格式的配置文件来创建DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();System.out.println("读取之前");for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}System.out.println("读取之后");XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);;reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\spring_bean.xml"));for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}
第三种较为经典的容器,基于java配置类来创建

较为经典的容器,基于java配置类来创建,通过这个配置类创建会帮我们创建后处理器了来解析@Bean注解

   // ⬇️3.较为经典的容器,基于java配置类来创建public void testAnnotationConfigApplicationContext() {// 会自动加上5个后处理器// org.springframework.context.annotation.internalConfigurationAnnotationProcessor// org.springframework.context.annotation.internalAutowiredAnnotationProcessor// org.springframework.context.annotation.internalCommonAnnotationProcessor// org.springframework.context.event.internalEventListenerProcessor// org.springframework.context.event.internalEventListenerFactoryAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
// 单元测试的过程中如果要解析一些Spring注解,比如@Configuration的时候不要把相关类定义到写单元测试类的内部类,会读取不到
@Configuration
class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2(Bean1 bean1) {Bean2 bean2 = new Bean2();bean2.setBean1(bean1);return bean2;}
}class Bean1 {}class Bean2 {private Bean1 bean1;public Bean1 getBean1() {return bean1;}public void setBean1(Bean1 bean1) {this.bean1 = bean1;}
}
第四种较为经典的容器,基于java配置类来创建,并且还可以用于web环境
// 模拟了 springboot web项目内嵌Tomcat的工作原理public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);// 防止程序终止System.in.read();}@Configuration
class WebConfig {@Bean// 1. WebServer工厂public ServletWebServerFactory servletWebServerFactory() {return new TomcatServletWebServerFactory();}@Bean// 2. web项目必备的DispatcherServletpublic DispatcherServlet dispatcherServlet() {return new DispatcherServlet();}@Bean// 3. 将DispatcherServlet注册到WebServer上public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {return new DispatcherServletRegistrationBean(dispatcherServlet, "/");}@Bean("/hello")public Controller controller1() {return (request, response) -> {response.getWriter().println("hello");return null;};}
}

相关文章:

  • 通付盾入选苏州市网络和数据安全免费体验目录,引领企业安全能力跃升
  • ubuntu20.04(ROS noetic版)安装cartographer
  • leetcode28. 找出字符串中第一个匹配项的下标_简单KMP
  • 基于Django的权限管理平台
  • Pgvector+R2R搭建RAG知识库
  • 问道数码兽 怀旧剧情回合手游源码搭建教程(反查重优化版)
  • 前缀和-724.寻找数组的中心下标-力扣(LeetCode)
  • OpenAI图像生成gpt-image-1登场,开启创意新可能
  • GPT-4o最新图像生成完全指南:10大应用场景与提示词模板
  • 【Vue】TypeScript与Vue3集成
  • Java学习手册:JSON 数据格式基础知识
  • 1Panel+Halo快速部署:简化服务器管理与网站搭建流程探索
  • 并发设计模式实战系列(6):读写锁
  • 立马耀:通过阿里云 Serverless Spark 和 Milvus 构建高效向量检索系统,驱动个性化推荐业务
  • 设计仿真 | Adams回调函数功能解析
  • 上岸率85%+,25西电先进材料与纳米科技学院(考研录取情况)
  • 通过阿里云Milvus与通义千问VL大模型,快速实现多模态搜索
  • ARINC818协议一些说明综述
  • QMT学习课程Day1
  • 针对密码学的 EM 侧信道攻击
  • 双拥主题歌曲MV:爱我人民,爱我军
  • 女子隐私被“上墙”莫名遭网暴,网警揪出始作俑者
  • 特朗普称已为俄乌问题设最后期限,届时美国态度或生变
  • 贝壳:网传“深圳贝壳内部通知”不实
  • 宝龙地产:委任中金国际为境外债务重组新的独家财务顾问
  • 叶迪奇任陆金所控股董事长,赵容奭继续担任CEO