Spring实战 | Spring IOC不能说的秘密?

news/2024/5/18 17:50:44/文章来源:https://blog.csdn.net/superdangbo/article/details/133775504

国庆中秋特辑系列文章:

国庆中秋特辑(八)Spring Boot项目如何使用JPA

国庆中秋特辑(七)Java软件工程师常见20道编程面试题

国庆中秋特辑(六)大学生常见30道宝藏编程面试题

国庆中秋特辑(五)MySQL如何性能调优?下篇

国庆中秋特辑(四)MySQL如何性能调优?上篇

国庆中秋特辑(三)使用生成对抗网络(GAN)生成具有节日氛围的画作,深度学习框架 TensorFlow 和 Keras 来实现

国庆中秋特辑(二)浪漫祝福方式 使用生成对抗网络(GAN)生成具有节日氛围的画作

国庆中秋特辑(一)浪漫祝福方式 用循环神经网络(RNN)或长短时记忆网络(LSTM)生成祝福诗词

目录

  • 一、工作原理
  • 二、具体分析
  • 三、核心功能分析

Spring IOC(Inversion of Control,控制反转)是 Spring 框架的核心特性之一,它通过解耦和依赖注入的方式简化了应用的组件开发和维护。在 Spring 框架中,有两个主要的 IOC 容器实现:一个是基于 XML 配置文件的 BeanFactory,另一个是基于 Java 类的 ApplicationContext。

在这里插入图片描述

一、工作原理

这里我们以一个简单的案例来分析 Spring IOC 的工作原理。假设我们有一个简单的 Java 程序,需要用到一个数据持久层(DataAccess)和一个业务层(Service)。
首先,我们需要创建一个 Spring 配置文件(如:applicationContext.xml),在这个文件中,我们将 DataAccess 和 Service 作为 Bean 定义:

<bean id="dataAccess" class="com.example.DataAccessImpl"/>  
<bean id="service" class="com.example.ServiceImpl" property="dataAccess">  <property name="dataAccess" ref="dataAccess"/>  
</bean>  

在这个配置文件中,我们定义了两个 Bean:一个是 DataAccess 类型的 Bean,另一个是 Service 类型的 Bean。Service Bean 中的 dataAccess 属性通过 ref 属性指定为 DataAccess Bean。
接下来,我们需要在 Java 程序中创建一个 Spring 的 IOC 容器,并从中获取 DataAccess 和 Service Bean:

import com.example.DataAccess;  
import com.example.Service;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {  public static void main(String[] args) {  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  DataAccess dataAccess = (DataAccess) context.getBean("dataAccess");  Service service = (Service) context.getBean("service");// 使用 Service 进行业务操作  service.doSomething();  }  
}

在这个 Java 程序中,我们首先创建了一个 Spring 的 IOC 容器(ApplicationContext),然后通过 getBean 方法获取了 DataAccess 和 Service Bean。注意,由于 Service Bean 的 dataAccess 属性是通过 ref 属性指定为 DataAccess Bean,所以在获取 Service Bean 时,Spring 会自动将 DataAccess Bean 注入到 Service Bean 中。
现在,我们可以通过 Service 类的 doSomething 方法来调用 DataAccess 类的相关方法进行数据持久操作。这个过程就是 Spring IOC 的工作原理。Spring IOC 容器负责管理 Bean 的创建和管理,以及 Bean 之间的依赖关系,我们只需要关注业务逻辑的实现即可。
总结一下,Spring IOC 的核心思想是:不再由对象自己创建和管理它所依赖的对象,而是由外部(如 Spring 容器)负责注入依赖对象。这样可以大大简化对象的创建和管理,提高代码的可维护性和可扩展性。

二、具体分析

  1. 资源加载:Spring IOC 容器中的资源加载主要采用了模板设计模式和抽象工厂设计模式。在创建实例的托管和创建过程中,Spring 根据 XML 配置文件创建 Resource 对象,该对象中包含了 BeanDefinition 的信息。
// Resource 加载  
public Resource getResourceByPath(String path) {  if (path.startsWith("/")) {  path = path.substring(1);  }  Resource[] resources = getResources();  for (Resource resource : resources) {  if (resource.getPath().equals(path)) {  return resource;  }  }  return null;  
}
  1. BeanDefinition 的管理:Spring IOC 容器中的 BeanDefinition 是一个重要的组成部分,它用于描述 Bean 的定义,包括 Bean 的名称、类名、属性等信息。BeanDefinition 的管理主要通过 BeanDefinitionRegistry 和 BeanDefinitionReader 两个类实现。
// BeanDefinitionReader 读取 BeanDefinition  
public void readBeanDefinitions(Resource resource) throws BeansException, IOException {  if (!resource.exists()) {  return;  }  try (InputStream reader = resource.getInputStream()) {  while (reader.markSupported()) {  int marker = reader.mark();  if (marker == XMLBeanDefinitionReader.ROOT_ELEMENT_START_MARKER) {  // 创建 BeanDefinitionReader 对象  BeanDefinitionReader beanDefinitionReader = new BeanDefinitionReader(this);  // 开始解析 XML 文件中的 BeanDefinition  beanDefinitionReader.parse(reader);  } else if (marker == XMLBeanDefinitionReader.ROOT_ELEMENT_END_MARKER) {  // 解析结束  break;  }  }  }  
}
  1. Bean 的创建和管理:Spring IOC 容器中的 Bean 创建和管理主要通过 BeanFactory 类实现。BeanFactory 类包含了创建 Bean、获取 Bean、删除 Bean 等方法,它是 Spring IOC 容器的核心部分。
// BeanFactory 创建 Bean  
public Object getBean(String name) throws BeansException {  // 根据 Bean 名称获取 BeanDefinition  BeanDefinition beanDefinition = getBeanDefinition(name);  // 如果 BeanDefinition 不存在,抛出异常  if (beanDefinition == null) {  throw new NoSuchBeanDefinitionException(name);  }  // 创建 Bean  Object bean = createBean(name, beanDefinition);  // 返回 Bean  return bean;  
}
  1. 依赖注入:Spring IOC 容器中的依赖注入主要通过 DependencyAutowire 和 PropertyAutowire 两个类实现。DependencyAutowire 类用于自动注入依赖,而 PropertyAutowire 类用于自动注入属性。
// DependencyAutowire 注入依赖  
public void setDependency(String propertyName, @Qualifier @Nullable String[] qualifiedClassNames) {  // 获取 BeanDefinition  BeanDefinition beanDefinition = getBeanDefinition(propertyName);  // 如果 BeanDefinition 不存在,抛出异常  if (beanDefinition == null) {  throw new NoSuchBeanDefinitionException(propertyName);  }  // 获取依赖的 Bean  @Qualifier("'" + beanDefinition.getBeanClassName() + "'")  @Autowired  Object dependency = getBeanFactory().getBean(propertyName, Object.class);  // 设置依赖  setter.setValue(this, dependency);  
}
  1. 生命周期管理:Spring IOC 容器中的生命周期管理主要通过 Lifecycle 和 LifecycleCallback 两个接口实现。Lifecycle 接口定义了 Bean 的生命周期方法,如 start、stop 等;LifecycleCallback 接口则是一个回调接口,用于在 Bean 的生命周期方法执行前后执行特定的逻辑。
// Lifecycle 接口  
public interface Lifecycle {  void start() throws BeansException;  void stop() throws BeansException;  boolean isStarted();  boolean isStopped();  void destroy() throws BeansException;  
}

三、核心功能分析

由于 Spring IOC 核心代码较长,无法在这里全部展示。但我可以简要介绍一下 Spring IOC 的核心部分,并提供部分关键代码示例。

  1. BeanFactory 的创建:
    BeanFactory 是 Spring IOC 容器的基本实现,它负责管理 Bean 的创建和管理。创建过程主要包括以下几个步骤:
  • 读取 Spring 配置文件(如 applicationContext.xml),解析其中的 Bean 定义;
  • 创建一个 BeanDefinitionRegistry,用于存储解析后的 BeanDefinition;
  • 创建一个 BeanFactoryInstance,用于封装 BeanDefinitionRegistry 和其他 BeanFactory 的实例;
  • 调用 BeanFactoryInstance 的 getObjectForBeanName 方法,根据 BeanName 获取对应的 Bean 定义;
  • 通过 BeanDefinition 的 getBean 方法创建 Bean 实例;
  • 将 Bean 实例添加到 BeanFactory 的 singletonObjects 中,以 BeanName 为键。
    以下是创建 BeanFactory 的示例代码:
public class BeanFactoryImpl implements BeanFactory {  //... 省略其他代码...@Override  protected void createBeanFactory(String name, BeanDefinitionRegistry registry) throws BeansException {  // 创建并初始化一个 DefaultListableBeanFactory 实例  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();  beanFactory.setBeanDefinitionRegistry(registry);  beanFactory.setResourceAccess(new ClassPathResource(name, getClassLoader()));  beanFactory.setEnvironment(this.environment);  beanFactory.setApplicationContextName(name);  beanFactory.setParentBeanFactory(this);  beanFactory.setSingletonObjects(new ConcurrentHashMap<String, Object>());  beanFactory.setDefaultSingletonBeanName(name);  beanFactory.registerBeanDefinition(new RootBeanDefinition(beanFactory, name));  }  
}
  1. Bean 的生命周期:
    Bean 的生命周期主要包括以下几个阶段:
  • 实例化:根据 BeanDefinition 创建 Bean 实例;
  • 属性填充:将 BeanDefinition 中的属性值设置到 Bean 实例上;
  • 初始化:调用 Bean 的初始化方法,进行相关设置;
  • 依赖注入:将 Bean 的依赖关系注入到 Bean 实例上;
  • 销毁:当 Bean 没有引用时,调用 Bean 的 destroy 方法进行销毁。
    以下是 Bean 生命周期的示例代码:
public class BeanFactoryImpl implements BeanFactory {  //... 省略其他代码...@Override  protected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) throws BeansException {  // 根据 BeanDefinition 创建 Bean 实例  Object bean = beanDefinition.getBean();// 属性填充  for (PropertyValue propertyValue : beanDefinition.getPropertyValues()) {  bean = propertyValue.resolve(bean);  }// 初始化  bean = beanDefinition.initialize(bean);// 依赖注入  if (bean instanceof ConfigurableBeanFactory) {  ((ConfigurableBeanFactory) bean).mergeBeanDefinitions(beanDefinition.getResourceDescription());  }// 将 Bean 添加到 singletonObjects 中,以 BeanName 为键  synchronized (this.singletonObjects) {  this.singletonObjects.put(name, bean);  }return bean;  }  
}
  1. 依赖注入:
    Spring IOC 容器通过依赖注入(Dependency Injection,DI)的方式将 Bean 的依赖关系注入到 Bean 实例上。依赖注入主要有两种方式:构造器注入和 setter 方法注入。
    以下是依赖注入的示例代码:
public class BeanFactoryImpl implements BeanFactory {  //... 省略其他代码...@Override  protected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) throws BeansException {  //... 省略其他代码...// 依赖注入  if (bean instanceof ConfigurableBeanFactory) {  ((ConfigurableBeanFactory) bean).mergeBeanDefinitions(beanDefinition.getResourceDescription());  }//... 省略其他代码...  }  
}

以上是 Spring IOC 核心代码的简要分析和示例。要了解更多关于 Spring IOC 的详细信息,建议参考 Spring 官方文档和相关教程。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「Qt中文教程指南」如何创建基于Qt Widget的应用程序(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文描述了如何使用…

增强基于Cortex-M3的MCU以处理480 Mbps高速USB

通用串行总线&#xff08;USB&#xff09;完全取代了PC上的UART&#xff0c;PS2和IEEE-1284并行接口&#xff0c;现在已在嵌入式开发应用程序中得到广泛认可。嵌入式开发系统使用的大多数I / O设备&#xff08;键盘&#xff0c;扫描仪&#xff0c;鼠标&#xff09;都是基于USB的…

Mac热门软件推荐Paste mac 中文激活版 剪切板工具

Paste for Mac是一款运行在Mac OS平台上的剪切板小工具。它拥有华丽的界面效果&#xff0c;并且每一条记录可显示&#xff08;预览&#xff09;文本、图片等记录的完整内容。此外&#xff0c;Paste for Mac可以记录最近指定条数的剪切板信息&#xff0c;方便用户随时调用&#…

低功耗、高性能处理器RK3326、RK3308、RK2206、RK2108芯片可广泛应用于各种产品领域。

1、RK3326 一款低功耗、高性能的多媒体处理芯片。 RK3326采用4颗Cortex-A35CPU和一个Mali-G31 GPU核心&#xff0c;能够提供高效的处理性能和图形渲染能力&#xff0c;可广泛应用于各种便携式设备&#xff0c;如平板电脑、智能手机、掌机、AI智能音箱等领域。 详细参数 • 四核…

云原生安全应用场景有哪些?

当今数字化时代&#xff0c;数据已经成为企业最宝贵的资产之一&#xff0c;而云计算作为企业数字化转型的关键技术&#xff0c;其安全性也日益受到重视。随着云计算技术的快速发展&#xff0c;云原生安全应用场景也越来越广泛&#xff0c;下面本文将从云原生安全应用场景出发&a…

工业读写器如何选型?

随着工业自动化的迅速发展&#xff0c;库存管理、生产流程、质量管理等传统工作人工工作也逐渐由各种智能设备来替代管理。RFID技术作为非接触式数据传输的通信方式&#xff0c;也常常应用在工业场合之中。具体工业RFID读写器如何选型&#xff0c;有哪些选择要点呢?ANDEAWELL国…

VIT(Vision Transformer)学习-模型理解(一)

VIT (Vision Transformer) 模型论文代码(源码)从零详细解读&#xff0c;看不懂来打我_哔哩哔哩_bilibili VIT模型架构图 1.图片切分为patch 2. patch转化为embedding 1&#xff09;将patch展平为一维长度 2&#xff09;token embedding&#xff1a;将拉平之后的序列映射…

安防监控视频汇聚平台EasyCVR视频广场搜索异常,报错“通道未开启”的问题排查与解决

安防视频监控系统EasyCVR视频汇聚平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、…

【ARM Coresight 系列文章 9.1 -- ITM 仪器化跟踪宏单元详细介绍】

文章目录 1.1 ITM 介绍1.1.1 ITM 功能介绍1.1.2 Cortex-M ITM 的地址范围1.2 ITM 使用1.2.1 ITM 寄存器介绍1.2.2 Cortex-M7 ITM 代码示例1.2.3 Cortex-M33 ITM 代码示例1.1 ITM 介绍 在debug 调试阶段通常都是使用 printf(printk) 来进行进行 log 输出,然后定位问题。那么如…

柯桥学设计,室内设计当下,简约式的奢华正流行

清闲简练 石材原木的空间设计探索中强调与艺术美学的碰撞融合&#xff0c;Mohammad Alomran采用清爽的白色和温暖的奶油色调搭配&#xff0c;以简练当代的语言&#xff0c;实现优雅、简约的创意设计&#xff0c;形成空间独特的魅力。 J. SH 奢华在于细节&#xff0c;优雅在于…

软件测试生命周期包括哪些阶段?CMA、CNAS软件测试报告有什么作用?

在软件开发过程中&#xff0c;软件测试是至关重要的环节&#xff0c;它可以确保软件的质量和稳定性&#xff0c;从而为用户提供良好的使用体验。在本文中&#xff0c;我们将详细描述软件测试生命周期的各个阶段以及CMA、CNAS软件测试报告的作用。 一、软件测试生命周期一般包括…

通讯网关软件020——利用CommGate X2Mysql实现Modbus TCP数据转储Mysql

本文介绍利用CommGate X2MYSQL实现从Modbus TCP设备读取数据并转储至MYSQL数据库。CommGate X2MYSQL是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus TCP设备读取数据并转储至M…

每日一练 | 华为认证真题练习Day118

1、如下图所示网络&#xff0c;交换机配置信息如下&#xff0c;下列说法中正确的有&#xff1f;&#xff08;多选&#xff09; interface GigabitEthernet0/0/1 port hybrid pvid vlan 20 port hybrid untagged vlan 10 20 # interface GigabitEtherneto/0/2 port hybrid…

经典面试题第九更---Promise养猪场

前言&#xff1a; &#x1f921; 作者简介&#xff1a;我是Morning&#xff0c;计算机的打工人&#xff0c;想要翻身做主人 &#x1f648; &#x1f648; &#x1f648; &#x1f3e0; 个人主页&#xff1a; Morning的主页 &#x1f4d5;系列专栏&#xff1a; 前端…

Selenium + Pytest自动化测试框架实战!

前言# selenium自动化 pytest测试框架 本章你需要 一定的python基础——至少明白类与对象&#xff0c;封装继承一定的selenium基础——本篇不讲selenium&#xff0c;不会的可以自己去看selenium中文翻译网 测试框架简介# 测试框架有什么优点呢&#xff1a; 代码复用率高&am…

Maven系列第3篇:详解maven解决依赖问题

maven系列目标&#xff1a;从入门开始开始掌握一个高级开发所需要的maven技能。 这是maven系列第3篇。 我们先来回顾一下什么是maven&#xff1f; maven是apache软件基金会组织维护的一款自动化构件工具&#xff0c;专注服务于java平台的项目构件和依赖管理。 本文主要内容…

204318-14-9,依多曲肽,DOTA-TOC

DOTA-[Tyr3]-Octreotide&#xff0c;依多曲肽,DOTA-(酪氨酸3)-奥曲肽是一种重要的多肽分子&#xff0c;其结构与奥曲肽类似&#xff0c;具有多种重要的药理作用。由于其具有大量的羧基官能团和醇羟基官能团&#xff0c;可以与各种放射性核素结合&#xff0c;因此被广泛应用于放…

基于Springboot实现口腔牙诊所管理平台项目【项目源码+论文说明】计算机毕业设计

基于Springboot实现口腔牙诊所管理平台演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;口腔管理平台当然也不能排除在外。口腔管理平台是以实际运用为开发背景&…

物业一站式工单管理系统哪家好?如何提升物业管理和维修服务质量?

在物业管理和维修服务领域&#xff0c;一个高效便捷的工单管理系统扮演着至关重要的角色。它不仅方便了住户提交报修请求&#xff0c;还极大地提高了物业管理和维修团队的工作效率。本文将深入探讨“的修”一站式工单管理系统在物业管理和维修服务中的重要作用。 一、“的修”一…