Spring 之依赖注入底层原理

        Spring 框架作为 Java 开发中最流行的框架之一,其核心特性之一就是依赖注入(Dependency Injection,DI)。在Spring中,依赖注入是通过 IOC 容器(Inversion of Control,控制反转)来实现的。本文将详细介绍Spring的依赖注入底层原理,并提供源码示例。

什么是依赖注入

        依赖注入是一种设计模式,它将对象之间的依赖关系从代码中移除,并由容器来管理这些依赖关系。依赖注入的主要目的是降低代码的耦合度,使代码更加灵活和可维护。

        在 Java 中,依赖通常是通过构造函数或者 Setter 方法来注入的。使用依赖注入,我们可以将对象的创建和依赖关系的管理分离开来,从而使得代码更加容易测试和维护。

实现原理

        Spring的依赖注入是通过 IOC 容器来实现的。在Spring中,IOC 容器负责创建和管理对象,以及管理对象之间的依赖关系。

IOC 容器

        IOC 容器是指用于管理对象和依赖关系的容器。Spring提供了多种 IOC 容器实现,包括 BeanFactory 和 ApplicationContext 等。

        BeanFactory 是 Spring 中最基本的 IOC 容器,它提供了基本的 IOC 功能。

        ApplicationContext 则是BeanFactory的扩展,它提供了更多的功能,如事件发布、国际化支持、AOP等。

        在 Spring 中,BeanFactory 和 ApplicationContext 都是通过反射来实例化对象,并通过依赖注入来管理对象之间的依赖关系。

Bean定义

        在 Spring 中,每个被管理的对象都需要有一个对应的 Bean 定义。Bean定义是一个元数据,它描述了一个 Bean 的类型、属性、依赖关系等信息。

        Bean 定义通常是通过XML配置文件、 Java 配置类或者注解来定义的。下面是一个使用 XML 配置文件定义 Bean 的示例:

<bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository"/>
</bean>

<bean id="userRepository" class="com.example.UserRepositoryImpl"/>
复制代码

在上面的示例中,我们定义了一个名为 userService的Bean,它的类型是com.example.UserService。它依赖于另一个名为userRepository的Bean,类型是com.example.UserRepositoryImpl。

依赖注入

        在 Spring 中,依赖注入是通过反射来实现的。当 IOC 容器创建 Bean 时,它会检查 Bean 定义中所声明的依赖关系,并尝试通过反射来注入这些依赖关系。

依赖注入通常分为三种方式:构造函数注入、Setter 方法注入和字段注入。

构造函数注入

        构造函数注入是最常见的依赖注入方式。在 Spring 中,我们可以通过构造函数来注入 Bean 的依赖关系。当 IOC 容器创建 Bean 时,它会检查 Bean 定义中所声明的构造函数,并尝试通过反射来调用这个构造函数,并将依赖关系作为参数传递进去。

下面是一个使用构造函数注入的示例:

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // ...
}
复制代码

在上面的示例中,我们定义了一个 UserService 类,并将 UserRepository 依赖关系通过构造函数注入进去。

Setter方法注入

        Setter 方法注入是另一种常见的依赖注入方式。我们可以通过 Setter 方法来注入Bean的依赖关系。当 IOC 容器创建Bean时,它会检查 Bean 定义中所声明的 Setter 方法,并尝试通过反射来调用这个 Setter 方法,并将依赖关系作为参数传递进去。

下面是一个使用Setter方法注入的示例:

public class UserService {
    private UserRepository userRepository;

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // ...
}
复制代码

在上面的示例中,我们定义了一个 UserService 类,并将 UserRepository 依赖关系通过 Setter 方法注入进去。

字段注入

        字段注入是一种不太常见的依赖注入方式。我们可以通过字段来注入Bean的依赖关系。当 IOC 容器创建 Bean 时,它会尝试通过反射来注入这些字段。

下面是一个使用字段注入的示例:

public class UserService {
    @Autowired
    private UserRepository userRepository;

    // ...
}
复制代码

在上面的示例中,我们使用了 @Autowired 注解来将 UserRepository 依赖关系注入到 userService 对象中的 userRepository 字段中。

生命周期回调

在Spring中,Bean生命周期包括四个阶段:实例化、属性赋值、初始化、销毁。在这些阶段中,Spring 提供了多个回调方法,以便我们在 Bean 的生命周期中进行一些自定义操作。

下面是一些常用的Bean生命周期回调方法:

实例化:Bean 实例化之后,Spring 会调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法。

属性赋值:在Bean实例化之后,Spring 会将 Bean 定义中所声明的属性值赋值给 Bean 对象。

初始化:在 Bean 属性赋值之后,Spring 会调用 InitializingBean 的 afterPropertiesSet 方法或者 @Bean 注解的 initMethod 方法。

销毁:在 IOC 容器关闭时,Spring 会调用 DisposableBean 的 destroy 方法或者 @Bean 注解的 destroyMethod方 法。

下面是一个实现 InitializingBean 和 DisposableBean 接口的示例:

public class UserService implements InitializingBean, DisposableBean {
    private UserRepository userRepository;

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void afterPropertiesSet() throws Exception {
        // 在Bean属性赋值之后,执行一些初始化操作
    }

    public void destroy() throws Exception {
        // 在 IOC 容器关闭时,执行一些销毁操作
    }

    // ...
}
复制代码

注解

         在 Spring 中,我们可以使用注解来简化 Bean 定义和依赖注入的过程。Spring 提供了多个注解来实现依赖注入和生命周期回调等功能。

下面是一些常用的 Spring 注解:

@Component:用于标记一个类为 Bean。

@Autowired:用于标记一个字段、构造函数或者 Setter 方法需要进行依赖注入。

@Qualifier:当存在多个相同类型的 Bean 时,用于指定依赖注入的具体实现。

@Value:用于注入一个常量值。

@PostConstruct:用于标记一个方法为 Bean 初始化方法。

@PreDestroy:用于标记一个方法为 Bean 销毁方法。

下面是一个使用注解的示例:

@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @PostConstruct
    public void init() {
        // 在Bean属性赋值之后,执行一些初始化操作
    }

    @PreDestroy
    public void destroy() {
        // 在 IOC 容器关闭时,执行一些销毁操作
    }

    // ...
}
复制代码

源码示例

下面是一个使用Spring的依赖注入功能的示例:

@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public void save(User user) {
        userRepository.save(user);
    }
}

@Component
public class UserRepositoryImpl implements UserRepository {
    public void save(User user) {
        // 保存用户信息
    }
}

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService();
    }

    @Bean
    public UserRepository userRepository() {
        return new UserRepositoryImpl();
    }
}

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        User user = new User();
        userService.save(user);
    }
}

复制代码

        在上面的示例中,我们使用了 @Component 注解标记了 UserService 和 UserRepositoryImpl 两个类为 Bean。在 AppConfig 类中,我们使用 @Bean 注解来定义了 UserRepository 和 UserService 两个 Bean。在 Main 类中,我们使用 AnnotationConfigApplicationContext 来创建 IOC 容器,并通过依赖注入来获取 UserService 对象,并调用它的 save 方法。

总结

        本文详细介绍了 Spring 的依赖注入底层原理,并提供了源码示例。通过本文的学习,我们可以更好地理解 Spring 的依赖注入机制,以及如何在实际开发中使用它来降低代码的耦合度,使代码更加灵活和可维护。

 

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

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

相关文章

电动牙刷语音芯片,音乐播放ic选型?

牙医认为每天刷牙两次对于口腔健康至关重要。但是有些人会因为不良的刷牙习惯而受害&#xff0c;比如刷牙时间不够长。而刷牙不当会导致牙齿出现问题&#xff0c;例如蛀牙、污渍和口臭。 为了保护牙齿健康&#xff0c;很多家庭开始尝试使用电动牙刷。电动牙刷通过嗡嗡地振动消…

springboot2.7及springboot3中自动配置的变化

大家在面试中问到springboot如何实现的自动配置 诶&#xff0c;不要傻背错八股了&#xff0c;以往 入口类上的SpringBootApplication注解引入EnableAutoConfiguration&#xff0c;再 Import({AutoConfigurationImportSelector.class}) &#xff0c;其中代码实现根据META-INF/sp…

实战案例|聚焦攻击面管理,腾讯安全威胁情报守护头部券商资产安全

金融“活水”润泽千行百业&#xff0c;对金融客户来说&#xff0c;由于业务场景存在特殊性和复杂性&#xff0c;网络安全必然是一场“持久战”。如何在事前做好安全部署&#xff0c;构建威胁情报分析的防护体系至为重要&#xff0c;实现更为精准、高效的动态防御。 客户名片 …

Java实现打印杨辉三角形,向左、右偏的平行四边形这三个图形代码程序

目录 前言 一、打印杨辉三角形 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 二、向左偏的平行四边形 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 三、向右偏的平行四边形 1.1运行流程&#xff08;思想&#xff09; 1.2代…

一个评测模型+10个问题,摸清盘古、通义千问、文心一言、ChatGPT的“家底”!...

‍数据智能产业创新服务媒体——聚焦数智 改变商业毫无疑问&#xff0c;全球已经在进行大模型的军备竞赛了&#xff0c;“有头有脸”的科技巨头都不会缺席。昨天阿里巴巴内测了通义千问&#xff0c;今天华为公布了盘古大模型的最新进展。不久前百度公布了文心一言、360也公布了…

网络系统集成综合实验(六)| 访问控制列表ACL配置

目录 一、前言 二、实验目的 三、实验需求 四、实验步骤与现象 &#xff08;一&#xff09;基本ACL实验 Step1&#xff1a;构建拓扑图如下&#xff1a; Step2&#xff1a;PC的IP地址分别配置如下&#xff1a; Step3&#xff1a;路由器的IP地址配置如下 Step4&#xff…

十、CNN卷积神经网络实战

一、确定输入样本特征和输出特征 输入样本通道数4、期待输出样本通道数2、卷积核大小33 具体卷积层的构建可参考博文&#xff1a;八、卷积层 设定卷积层 torch.nn.Conv2d(in_channelsin_channel,out_channelsout_channel,kernel_sizekernel_size,padding1,stride1) 必要参数&a…

大数据五次作业回顾

文章目录1. 大数据作业11.本地运行模式部分2. 使用scp安全拷贝部分2. 大数据作业21、Rrsync远程同步工具部分2、xsync集群分发脚本部分3、集群部署部分3. 大数据作业31. 配置历史服务器及日志2. 日志部分3. 其他4. 大数据作业4编写本地wordcount案例一、源代码二、信息截图5. 大…

matlab流场可视化后处理

1流体中标量的可视化 流体力学中常见的标量为位置、速度绝对值、压强等。 1.1 云图 常用的云图绘制有pcolor、image、imagesc、imshow、contourf等函数。 这里利用matlab自带的wind数据作为演示案例&#xff0c;显示二维云图的速度场。 close all load wind x2x(:,:,5);y2y…

介绍MSYS2 在windows下与使用

系列文章目录 文章目录系列文章目录前言一、MSYS下载二、安装三、使用MSYS2安装CMake工具前言 MSYS的独立改写版本 MSYS2 &#xff08;Minimal SYStem 2&#xff09; 是一个MSYS的独立改写版本&#xff0c;主要用于 shell 命令行开发环境。同时它也是一个在Cygwin &#xff08…

闭关修炼(0.0 pytorch基础学习)1

基于官网pytorch.org pytorch 动态 比较优秀 py3.7支持是最多的啦 原来anaconda 是蟒蛇的意思 细思极恐 python 是蛇 yi Introduction to PyTorch Tensors — PyTorch Tutorials 2.0.0cu117 documentation omygaga 英语极差 哈哈哈 tensor 多维数组 矩阵二维数组 Tensor…

G761-3005B伺服阀放大器

G761-3005B伺服阀放大器&#xff0c;两级设计能够实现高水平设备性能、更快的周期时间和更高的准确性&#xff0c;最终为客户带来更高的生产效率 双线圈力矩马达高可靠性冗余设计 力矩马达配置双精度喷嘴精确流量控制和可预测性 干式力矩马达设计消除力矩马达气隙中可能导致…

数据结构-二叉树(前中后层序遍历-代码实现)

一、概要 二叉树的遍历方式包括前序遍历、中序遍历、后序遍历和层序遍历&#xff0c;具体定义如下&#xff1a; 前序遍历&#xff1a;先访问根节点&#xff0c;然后按照前序遍历的方式递归访问左子树和右子树。 中序遍历&#xff1a;先按照中序遍历的方式递归访问左子树&#…

Spring————java的反射机制,Spring的IOC和DI

一、认识Spring 1.1、Spring家族 SpringFramework&#xff1a; Spring框架&#xff1a;是Spring中最早核心的技术&#xff0c;也是所有其他技术及的基础。 SpringBoot:Spring是用来简化开发。而SpringBoot是来帮助Spring在简化的基础上能更快速进行开发。 SpringCloud&#xf…

v851s gpio 应用程序编写

1. 查看硬件电路图SCH_Schematic1_2022-11-23 &#xff0c;查找合适的gpio 作为使用pin 在这里我们选取 GPIOH14&#xff08;注意目前开发使用这个pin 作为触摸屏的pin脚&#xff0c;需要将触摸屏connect断开&#xff09; &#xff0c;因为 可以通过排插使用杜邦线将其引出&am…

Maven高级-属性多环境配置与应用

Maven高级-属性&多环境配置与应用4&#xff0c;属性4.1 属性4.1.1 问题分析4.1.2 解决步骤步骤1:父工程中定义属性步骤2:修改依赖的version4.2 配置文件加载属性步骤1:父工程定义属性步骤2:jdbc.properties文件中引用属性步骤3:设置maven过滤文件范围步骤4:测试是否生效4.3…

mysql慢查询

目录标题如何收集慢SQL-- ELK体系收集慢日志分析SQL优化添加索引优化慢sql通过拆分冷热数据优化读写分离预防我们优化的思路是“收集——分析——优化——预防”了解完如何收集慢日志之后&#xff0c;就要开始分析 SQL 了。优化 SQL 的基础手段是 EXPLAIN&#xff0c;我们要收起…

Spark SQL实战(04)-API编程之DataFrame

1 SparkSession Spark Core: SparkContext Spark SQL: 难道就没有SparkContext&#xff1f; 2.x之后统一的 package com.javaedge.bigdata.chapter04import org.apache.spark.sql.{DataFrame, SparkSession}object SparkSessionApp {def main(args: Array[String]): Unit …

认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】

前言 分布式微服务系统中添加登录和注册&#xff0c;&#xff08;这里暂未完成分布式情况下用户登录信息情况记录&#xff09;&#xff0c;主要记录&#xff1a;一个微服务专门管理用户信息。需要通过远程调用的形式&#xff0c;来完成用户注册以及登录流程&#xff0c;同时密…

【故障定位】基于多元宇宙算法的主动配电网故障定位方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…