spring IOC(实现原理)

文章目录

  • 依赖注入
  • 控制反转
    • 相关
    • Spring 框架的 Bean管理的配置文件方式
    • 实例化Bean的三种方式
      • 无参构造器实例化
      • 静态工厂方法实例化
      • 实例工厂方法实例化
      • 静态和动态对比
    • 注解
      • 常用注解
      • 纯注解
  • 其它问题
    • 为什么p 命名空间方式需要无参构造

依赖注入

**依赖注入(DI)**是Spring框架核心功能之一,它允许对象间的依赖关系通过配置或代码在运行时动态注入,而不是通过对象内部硬编码。这种方法减少了代码间的耦合,增加了灵活性和可重用性。

依赖注入强调的是对象的依赖关系由外部来管理和提供,而不是由对象自身负责创建依赖对象。通过这种方式,可以降低对象之间的耦合度。即下面的方式也属于依赖注入。

常见的依赖注入方式

  • 构造函数注入:通过类的构造函数将依赖对象传递给该类。在对象实例化时,容器会调用相应的构造函数,并传入依赖对象的实例。
public class ProductService {private final ProductRepository productRepository;public ProductService(ProductRepository productRepository) {this.productRepository = productRepository;}// 业务方法
}
  • Setter 方法注入:利用类的 setter 方法将依赖对象设置到该类中。容器先创建对象实例,然后调用 setter 方法来注入依赖对象。
public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}// 业务方法
}

xml依赖注入

  • <property>
  • <list><value></value></list>
  • <map><entry key=' ' value=' '></map>
  • <array><value></value></array>
  • <set><value></value></set>
  • <props><prop key=' '>值</prop></props>
---------------Student类------------------
public class Student {private String name;private Adress address;private String[] books;private List<String> hobbies;private Map<String,String> card;private Set<String> games;private String wife;private Properties info;//getter,setter,无参and全参构造}
---------------Teacher类------------------
public class Teacher {private String name;private int age;//getter,setter,无参and全参构造}
---------------applicationContext.xml------------------<bean id="adress" class="com.luxiya.Adress"><property name="address" value="空中花园"/></bean><!-- 需要相应的构造函数--><bean id="teacher" class="com.luxiya.Teacher" c:name="luxiya" c:age="18"/><!-- 需要相应的构造函数--><bean id="teacher1" class="com.luxiya.Teacher"><constructor-arg name="name" value="luxiya-constructor"/><constructor-arg name="age" value="188"/></bean><!-- 需要空参构造--><bean id="teacher2" class="com.luxiya.Teacher" p:name="zhihuiguan" p:age="19"></bean><bean id="student" class="com.luxiya.Student"><property name="name" value="luxiya"/><property name="address" ref="adress"/><property name="books"><array><value>java</value><value>python</value></array></property><property name="hobbies"><list><value>打篮球</value><value>打游戏</value></list></property><property name="card"><map><entry key="身份证" value="123456789"/><entry key="银行卡" value="123456789"/></map></property><property name="games"><set><value>LOL</value><value>DOTA</value></set></property><property name="wife"><null/></property><property name="info"><props><prop key="name">luxiya</prop><prop key="age">18</prop></props></property></bean>
---------------测试类------------------
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println(teacher.toString());
Teacher teacher1 = (Teacher) context.getBean("teacher1");
System.out.println(teacher1.toString());
Teacher teacher2 = (Teacher) context.getBean("teacher2");
System.out.println(teacher2.toString());

控制反转

​ 在传统的程序设计中,当一个对象(A)需要使用另一个对象(B)的功能时,通常会在对象 A 内部主动创建对象 B 的实例,即对象 A 对对象 B 的创建和生命周期管理具有控制权。而在控制反转的思想下,对象 A 所依赖的对象 B 的创建、实例化以及依赖关系的建立,不再由对象 A 自身负责,而是由一个外部的容器(比如 Spring 容器)来负责管理。这样一来,对象 A 获得依赖对象 B 的过程被反转了,控制权从对象 A 转移到了外部容器,这就是 “控制反转” 名称的由来。

​ IoC 容器负责创建对象、管理对象的生命周期,并在适当的时候将对象注入到需要它们的其他对象中。应用程序中的各个组件(对象)只需要关注自身的业务逻辑,而不需要关心依赖对象的创建和获取过程。容器会根据配置信息(如 XML 配置文件或注解)来确定对象之间的依赖关系,并自动完成对象的实例化和注入。

  • XML 配置:在 Spring 早期,XML 是配置 Bean 的主要方式。通过编写 XML 文件,**将 Bean 的定义信息(如 Bean 的类名、依赖关系、属性值等)与 Bean 的实现类分离开来。**这样做的好处是可以在不修改实现类代码的情况下,修改 Bean 的配置信息,便于对系统进行维护和扩展。但缺点是 XML 文件可能会变得冗长复杂,增加了配置的难度和维护成本。
  • 注解配置:随着 Spring 框架的发展,注解配置逐渐流行起来。使用注解(如 @Component@Service@Repository@Autowired 等)可以直接在实现类中定义 Bean 的信息和依赖关系,将 Bean 的定义和实现合二为一。这种方式减少了大量的 XML 配置,使得代码更加简洁,开发效率更高,实现了所谓的 “零配置”(或者说减少了显式配置)。

相关

ApplicationContext 接口,工厂的接口,使用该接口可以获取到具体的 Bean 对象。该接口下有两个具体的实现类。

ClassPathXmlApplicationContext,加载类路径下的 Spring 配置文件。(注:ClassPathXmlApplicationContext在读取application.xml文件时,就会自动创建bean实例)

FileSystemXmlApplicationContext,加载本地磁盘下的 Spring 配置文件。

Spring 框架的 Bean管理的配置文件方式

  1. id 属性

id 属性为每个 Bean 提供了一个唯一的标识符。

  1. class 属性

class 属性指定了 Bean 对象的全限定类名。在这个例子中,com.example.service.UserService 就是 UserService 类的完整路径,Spring 容器会根据这个路径来创建相应的 Bean 实例。

  1. scope 属性
  • singleton(单例):这是 scope 属性的默认值。当 scope 设置为 singleton 时,Spring 容器只会创建该 Bean 的一个实例,并且在整个应用程序的生命周期中都使用这个实例。
  • prototype(多例):当 scope 设置为 prototype 时,每次从 Spring 容器中获取该 Bean 时,容器都会创建一个新的实例。
  1. init - methoddestroy - method 属性
  • init - method:当 Bean 被加载到 Spring 容器时,会调用 init - method 属性指定的方法。
  • destroy - method:当 Bean 从 Spring 容器中移除时,会调用 destroy - method 属性指定的方法。
    <!-- 定义一个单例的 UserService Bean --><bean id="userServiceSingleton" class="com.example.service.UserService"scope="singleton"init-method="init"destroy-method="destroy"></bean><!-- 定义一个多例的 UserService Bean --><bean id="userServicePrototype" class="com.example.service.UserService"scope="prototype"></bean>
-----------------测试------------------
public class UserService {// 初始化方法public void init() {System.out.println("UserService 初始化");}// 销毁方法public void destroy() {System.out.println("UserService 销毁");}
}

实例化Bean的三种方式

无参构造器实例化

这是 Spring 中最基本的实例化 Bean 的方式,Spring 容器会调用 Bean 类的无参构造器(如果没有指定其他构造器)或者指定的有参构造器来创建 Bean 对象。

public class UserService {public UserService() {System.out.println("UserService实例化");}
}
-------------application.xml--------------
<bean id="userService" class="com.luxiya.demo.UserService"/>
-------------测试类--------------ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = (UserService) context.getBean("userService");

静态工厂方法实例化

使用一个静态工厂方法来创建 Bean 对象。静态工厂方法是类中的一个静态方法,该方法会返回一个对象实例。Spring 容器会调用这个静态工厂方法来获取 Bean 对象。

public class StaticFactory {public static UserService getUserService(){System.out.println("静态工厂创建");return new UserService();}
}
-------------application.xml--------------<!-- 静态工厂--><bean id="uSstatic" class="com.luxiya.demo.StaticFactory" factory-method="getUserService"/>
-------------测试类--------------ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = (UserService) context.getBean("uSstatic");

实例工厂方法实例化

使用一个实例工厂的方法来创建 Bean 对象。首先需要创建一个工厂类的实例,然后调用该实例的方法来创建 Bean 对象。

-------------application.xml--------------
<!--动态工厂-->
<bean id="dFactory" class="com.luxiya.demo.DFactory"/>
<bean id="useDF" factory-bean="dFactory" factory-method="getUserService"/>
-------------测试类--------------
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("useDF");

静态和动态对比

  • 静态工厂:静态工厂方法相对固定,因为它是类的静态方法,不能根据不同的实例状态进行不同的处理。通常适用于创建一些通用的、不依赖于实例状态的对象。不依赖于工厂类的实例。
  • 动态工厂:动态工厂方法可以根据工厂类实例的不同状态来创建不同的 Bean 对象,具有更高的灵活性。例如,工厂类可以有不同的属性值,根据这些属性值在实例工厂方法中创建不同类型或配置的 Bean 对象。依赖于工厂类的实例。

注解

常用注解

@Component 普通的类

@Controller 表现层@Service 业务层

@Repository 持久层

依赖注入常用的注解

@Value 用于注入普通类型(String,int,double 等类型)

@Autowired 默认按类型进行自动装配(引用类型)

@Qualifier 和@Autowired 一起使用,强制使用名称注入

@Resource Java 提供的注解,也被支持。使用 name 属性,按名称注入

对象生命周期(作用范围)注解

@Scope 生命周期注解,取值 singleton(默认值,单实例)和 prototype(多

例)

初始化方法和销毁方法注解(了解)

@PostConstruct 相当于 init-method

@PreDestroy 相当于 destroy-method

@Service
public class TeacherService {public TeacherService() {System.out.println("TeacherService初始化");}
}-----------application.xml----------
<!--开启注解扫描-->
<context:component-scan base-package="com.luxiya.demo"/>
-----------------测试类--------------
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TeacherService teacherService = (TeacherService) context.getBean("teacherService");

纯注解

纯注解的方式是微服务架构开发的主要方式,所以也是非常的重要。纯注解的目的是替换掉所有的配置文件。但是需要编写配置类。

常用的注解总结

@Configuration 声明是配置类

@ComponentScan 扫描具体包结构的。也可以扫描多个包@ComponentScan(value ={“com.qcbyjy.demo4”,“com.qcbyjy.demo3”})

@Import 注解 Spring 的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类

@Bean 注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到 IOC 容器中

------------demo包下的配置类--------------
@Configuration
@ComponentScan(basePackages = "com.luxiya.demo")
@Import(SpringConfig2.class)
public class SpringCofig {@Bean(name="dataSource")public DataSource createDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;}
}
-------------------基础测试--------------ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);Student student = (Student) context.getBean("student");
-------------demo2包下的配置类----------------
@Configuration
@ComponentScan(basePackages = "com.luxiya.demo2")
public class SpringConfig2 {
}
//demo2包下
@Data
@Component
public class Course {@Value("java")private String name;public Course(){System.out.println("Course初始化");}
}
//demo包下
@Component
@Data
public class Student {@Value("luxiya")private String name;public Student() {System.out.println("Student实例化");}
}
------------测试@Import注解-------------ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);Course course = (Course) context.getBean("course");------------测试@Bean注解-------------ApplicationContext context = new AnnotationConfigApplicationContext(SpringCofig.class);
//        Student student = (Student) context.getBean("student");
//        Course course = (Course) context.getBean("course");// 从应用上下文中获取 DataSource 对象DataSource dataSource = context.getBean("dataSource", DataSource.class);// 验证 DataSource 对象是否为 DruidDataSource 类型if (dataSource instanceof DruidDataSource) {DruidDataSource druidDataSource = (DruidDataSource) dataSource;System.out.println("Druid DataSource 配置信息:");System.out.println("Driver Class Name: " + druidDataSource.getDriverClassName());System.out.println("URL: " + druidDataSource.getUrl());System.out.println("Username: " + druidDataSource.getUsername());System.out.println("Password: " + druidDataSource.getPassword());}

其它问题

为什么p 命名空间方式需要无参构造

原因:在 Spring 中,当你使用属性注入(如你给出的 p 命名空间方式)时,Spring 容器在创建 Bean 实例的过程中,默认情况下会尝试使用无参构造函数来实例化对象,之后再通过 setter 方法进行属性注入。

Spring 容器在创建 Bean 实例时,主要有以下几个步骤:

  1. 实例化对象:Spring 需要先创建 Bean 对应的 Java 对象实例,一般情况下,它会优先尝试使用无参构造函数来创建对象。这是因为无参构造函数可以简单直接地创建对象,不需要额外的参数信息。
  2. 属性注入:在对象实例创建完成后,Spring 会根据配置(如 p 命名空间指定的属性值)调用对象的 setter 方法将属性值注入到对象中。

所以,当你使用 p 命名空间进行属性注入时,Spring 首先会尝试调用无参构造函数来创建 Teacher 对象,若类中没有无参构造函数,就会抛出 No default constructor found 这样的异常。

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

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

相关文章

ESP8266 NodeMCU 与 Atmega16 微控制器连接以发送电子邮件

NodeMCU ESP8266 AVR 微控制器 ATmega16 的接口 Atmega16 是一款低成本的 8 位微控制器,比以前版本的微控制器具有更多的 GPIO。它具有所有常用的通信协议,如 UART、USART、SPI 和 I2C。由于其广泛的社区支持和简单性,它在机器人、汽车和自动化行业有广泛的应用。 Atmega1…

C++查看动态库导出哪些函数以及动态库导出形式

1、查看动态库导出哪些函数 1.1、在 Windows 和 Linux 上&#xff0c;可以使用不同的方法来查看动态库&#xff08;.dll 或 .so&#xff09;导出的函数 Windows&#xff1a;使用 dumpbin&#xff1a;Windows 提供了 dumpbin 工具&#xff08;Visual Studio 自带&#xff09;&…

【使用hexo模板创建个人博客网站】

使用hexo模板创建个人博客网站 环境准备node安装hexo安装ssh配置 使用hexo命令搭建个人博客网站hexo命令 部署到github创建仓库修改_config.yml文件 编写博客主题扩展 环境准备 node安装 进入node官网安装node.js 使用node -v检查是否安装成功 安装成功后应该出现如上界面 …

【Linux】http 协议

目录 一、http协议 &#xff08;一&#xff09;http 协议的概念 &#xff08;二&#xff09;URL的组成 &#xff08;三&#xff09;urlencode 和 urldecode 二、http 的协议格式 &#xff08;一&#xff09;http 请求方法 &#xff08;二&#xff09;http 响应状态码 &a…

什么是时序数据库?有哪些时序数据库?常见的运用场景有哪些?

时序数据库 什么是时序数据库&#xff1f; 时序数据库&#xff08;Time Series Database, TSDB&#xff09;是专门针对时间序列数据&#xff08;按时间顺序记录的数据点&#xff09;进行存储和管理的数据库。这类数据通常包含时间戳&#xff08;Timestamp&#xff09;和对应的…

【Linux】冯诺依曼体系与操作系统理解

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、冯诺依曼体系结构 二、操作系统 1. 操作系统的概念 2. 操作系统存在的意义 3. 操作系统的管理方式 4. 补充&#xff1a;理解系统调用…

Unity HDR颜色、基础颜色、强度强度、HDR面板Intensity之间的相互转换

目录 前言&#xff1a; 一、UnityHDR面板的规律 二、HDR与基础颜色转换&#xff0c;HDR强度获取&#xff0c;输入设置强度获取 1.基础色->HDR颜色 2.HDR颜色->基础色 3.获取HDR颜色在面板中的强度 4.获取HDR颜色在面板设置输入时的强度 前言&#xff1a; HDR&#…

c++进阶--map和set的使用

大家好&#xff0c;昨天我们学习了二叉搜索树&#xff0c;今天我们来学习一下map和set容器的使用。 目录 1. map和set的使⽤ 1.1 序列式容器和关联式容器 2. set系列的使⽤ 2.1 参考文档 2.2 set类的介绍 2.3 set的构造和迭代器 2.4 set的增删查 2.5 insert和迭代器…

Kylin麒麟操作系统服务部署 | NFS服务部署

以下所使用的环境为&#xff1a; 虚拟化软件&#xff1a;VMware Workstation 17 Pro 麒麟系统版本&#xff1a;Kylin-Server-V10-SP3-2403-Release-20240426-x86_64 一、 NFS服务概述 NFS&#xff08;Network File System&#xff09;&#xff0c;即网络文件系统。是一种使用于…

FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解

FPGA之Usb数据传输 Usb 通信 你也许会有疑问&#xff0c;明明有这么多通信方式和数据传输&#xff08;SPI、I2C、UART、以太网&#xff09;为什么偏偏使用USB呢? 原因有很多&#xff0c;如下&#xff1a; 1. 高速数据传输能力 高带宽&#xff1a;USB接口提供了较高的数据传…

生活反思公园散步与小雨遇记

《公园散步与小雨遇记》&#xff08;一&#xff09; 总收录于《生活小事灵感反思》与《生活小美好》 最近又新增一个习惯&#xff1a;每天至少走一小时 那天天气有雨&#xff0c;软件上显示在下雨&#xff0c;但是外面没雨&#xff0c;心想着大不了淋湿回来洗个头&#xff0c;…

夏门大学DeepSeek 手册:从社会大众到高校及企业的全面应用实践研究(附 PDF 下载)

这 3 份手册分别从 DeepSeek 大模型概念、技术与应用实践、DeepSeek 大模型赋能高校教学和科研、DeepSeek 大模型及其企业应用实践-企业人员的大模型宝典几个角度进行全面分析&#xff0c;可以结合着清华、北大系列相互对照着学习。 清华北大推出的 DeepSeek 教程&#xff08;…

微服务保护:Sentinel

home | Sentinelhttps://sentinelguard.io/zh-cn/ 微服务保护的方案有很多&#xff0c;比如&#xff1a; 请求限流 线程隔离 服务熔断 服务故障最重要原因&#xff0c;就是并发太高&#xff01;解决了这个问题&#xff0c;就能避免大部分故障。当然&#xff0c;接口的并发…

工作学习笔记:HarmonyOS 核心术语速查表(v14 实战版)

作为在 HarmonyOS 开发一线摸爬滚打的工程师&#xff0c;笔者在 v14 版本迭代中整理了这份带血的实战术语表。 一、架构基础术语速查 A 系列术语 术语官方定义笔者解读&#xff08;v14 实战版&#xff09;开发陷阱 & 解决方案abc 文件ArkCompiler 生成的字节码文件打包时…

驾校与无人机飞手培训机构合作开展低空业务技术详解

驾校与无人机飞手培训机构合作开展低空业务是一个创新的举措&#xff0c;旨在结合双方的资源和专业优势&#xff0c;为学员提供多元化的技能培训和业务拓展机会。以下是对这种合作模式下低空业务技术的详细解析&#xff1a; 一、合作背景与意义 1. 市场需求增长&#xff1a;随…

黄昏时间户外街拍人像Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色介绍 黄昏时分有着独特而迷人的光线&#xff0c;使此时拍摄的人像自带一种浪漫、朦胧的氛围 。通过 Lr 调色&#xff0c;可以进一步强化这种特质并根据不同的风格需求进行创作。Lr&#xff08;Lightroom&#xff09;作为专业的图像后期处理软件&#xff0c;提供了丰富的调色…

数据结构(队列)

数据结构&#xff08;队列&#xff09; 什么是队列&#xff1f; 队列和栈类似&#xff0c;也是一类特殊的线性表。特殊之处也是在于操作上。队列&#xff1a;只允许在一端进行插入数据操作&#xff08;入队&#xff09;&#xff0c;在另一端进行删除数据操作&#xff08;出队&…

DeepSeek R1-7B 医疗大模型微调实战全流程分析(全码版)

DeepSeek R1-7B 医疗大模型微调实战全流程指南 目录 环境配置与硬件优化医疗数据工程微调策略详解训练监控与评估模型部署与安全持续优化与迭代多模态扩展伦理与合规体系故障排除与调试行业应用案例进阶调优技巧版本管理与迭代法律风险规避成本控制方案文档与知识传承1. 环境配…

[Lc7_分治-快排] 快速选择排序 | 数组中的第K个最大元素 | 库存管理 III

目录 1. 数组中的第K个最大元素 题解 代码 2.库存管理 III 代码 1. 数组中的第K个最大元素 题目链接&#xff1a;215. 数组中的第K个最大元素 题目分析&#xff1a; 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要…

集合论--形式化语言里的汇编码

如果一阶逻辑是数学这门形式化语言里的机器码&#xff0c;那么集合论就是数学这门形式化语言里的汇编码。 基本思想&#xff1a;从集合出发构建所有其它。 构建自然数构建整数构建有理数构建实数构建有序对、笛卡尔积、关系、函数、序列等构建确定有限自动机(DFA) 全景图 常…