Spring框架实现依赖注入的原理

目录
  • 什么是依赖注入
  • 实现原理
    • IOC容器
    • Bean定义
    • 依赖注入
    • 构造函数注入
    • Setter方法注入
    • 字段注入
  • 生命周期回调
  • 注解
  • 总结

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 的依赖注入机制,以及如何在实际开发中使用它来降低代码的耦合度,使代码更加灵活和可维护。

到此这篇关于Spring框架实现依赖注入的原理的文章就介绍到这了,更多相关Spring依赖注入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring DI依赖注入过程解析

    目录 依赖简介 依赖注入 Spring DI依赖注入详解 依赖简介 一个典型的企业应用程序不是由一个单一的对象组成(或Spring的说法中的bean).即使是最简单的应用程序也只有几个对象一起工作来呈现最终用户看作是一个连贯的应用程序.如何从定义许多独立的bean定义到完全实现的应用程序,在这些应用程序中对象协作实现目标. 依赖注入 依赖注入(DI)是一个过程,通过这个过程,对象可以通过构造函数参数,工厂方法的参数或者在构造或返回对象实例后设置的属性来定义它们的依赖关系从工厂方法.然后容器在创建

  • Spring框架中IoC容器与DI依赖注入教程

    目录 一.Spring 是什么 1.1 什么是容器 1.2 什么是 IoC 二.理解 IoC 2.1 传统程序开发的问题 2.2 分析 2.3 控制反转式程序开发 2.4 对比总结规律 2.5 理解 Spring IoC 三.DI 概念说明 四.总结 一.Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework (Spring 框架),它是⼀个开源框架,有着活跃而庞大的社区,这就是它之所以能长久不衰的原因.Spring ⽀持⼴泛的应⽤场景,它可以让 Java

  • Spring入门基础之依赖注入

    目录 一.构造器注入 二.set注入 三.其他方式注入 (1)导入约束 (2)p命名注入 (3)c命名注入 一.构造器注入 在前几节已经做过了详细的说明讲解,我们先跳过 二.set注入 依赖注入 依赖: bean对象的创建以及管理都依赖于Spring IOC容器 注入: bean对象中的所有属性,都有容器进行注入 在前面我们已经见识过了 普通类型注入和 bean注入的方式,那么对于复杂类型List.数组类型.Map.Set属性等怎么进行注入呢? 我们先提供一个包含各种类型的实体类 Student

  • Spring依赖注入的几种方式分享梳理总结

    目录 环境 准备 设值注入 构造注入 总结 环境 Ubuntu 22.04 IntelliJ IDEA 2022.1.3 JDK 17.0.3 Spring 5.3.21 准备 创建Maven项目 test0706 . 修改 pom.xml 文件,添加依赖: ...... <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId>

  • 详解Spring依赖注入的三种方式以及优缺点

    目录 0.概述 1.属性注入 1.1 优点分析 1.2 缺点分析 2.Setter 注入 优缺点分析 3.构造方法注入 优点分析 总结 0.概述 在 Spring 中实现依赖注入的常见方式有以下 3 种: 属性注入(Field Injection): Setter 注入(Setter Injection): 构造方法注入(Constructor Injection). 它们的具体使用和优缺点分析如下. 1.属性注入 属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式,它的实现代码如下:

  • Spring依赖注入与第三方Bean管理基础详解

    目录 1. 注解开发依赖注入 1.1 使用@Autowired注解开启自动装配模式 1.2 使用@Qualifier注解指定要装配的bean名称 1.3 使用@Value实现简单类型注入 2. 注解开发管理第三方Bean 2.1 单独定义配置类 2.2 将独立的配置类加入核心配置 3.注解开发为第三方Bean注入资源 3.1 简单类型依赖注入 3.1.1 新建jdbc.properties文件 3.1.2 在配置类或者配置文件中加载属性文件. 3.1.3 使用EL表达式读取properties属

  • Spring配置与依赖注入基础详解

    目录 1.Spring配置 1.1.别名 1.2.Bean的配置 1.3.import 2.依赖注入(DI) 2.1.构造器注入 2.2.Set 注入(重点) 2.3.扩展的注入 2.4.Bean的作用域 1.Spring配置 1.1.别名 别名 alias 设置别名 , 为bean设置别名 , 可以设置多个别名 <!--设置别名:在获取Bean的时候可以使用别名获取--> <alias name="userT" alias="userNew"/&

  • 深入浅出讲解Spring框架中依赖注入与控制反转及应用

    目录 一. 概念: 1. 使用前: 2. 使用后: 二. 理解控制反转(Ioc): 三. IoC的应用方法 一. 概念: 依赖注入(Dependency Injection,DI)与控制反转(IoC)的含义相同,只不过是从两个角度描述的同一个概念.对于一个Spring初学者来说,这两种称呼都很难理解,我们通过简单的语言来描述这两个概念. 使用对比: 1. 使用前: 当某个Java对象(调用者)需要调用另一个Java对象(被调用者,就是被依赖对象)时,在传统模式下,调用者通常会采用"new被调用者

  • 理解Spring中的依赖注入和控制反转

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. IoC是什么 Ioc-InversionofControl,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内

  • Spring框架设值注入操作实战案例分析

    本文实例讲述了Spring框架设值注入操作.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <!-- Spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 --> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http:

  • 详解ASP.NET Core 中的框架级依赖注入

    1.ASP.NET Core 中的依赖注入 此示例展示了框架级依赖注入如何在 ASP.NET Core 中工作. 其简单但功能强大,足以完成大部分的依赖注入工作.框架级依赖注入支持以下 scope: Singleton - 总是返回相同的实例 Transient - 每次都返回新的实例 Scoped - 在当前(request)范围内返回相同的实例 假设我们有两个要通过依赖注入来进行工作的工件: PageContext - 自定义请求上下文 Settings - 全局应用程序设置 这两个都是非常

  • Spring quartz Job依赖注入使用详解

    Spring quartz Job依赖注入使用详解 一.问题描述: 使用Spring整合quartz实现动态任务时,想在job定时任务中使用某个service时,直接通过加注解@Component.@Autowired是不能注入的,获取的对象为Null.如下面的代码: @Component @PersistJobDataAfterExecution @DisallowConcurrentExecution public class TicketSalePriceLessThanLowestPri

  • spring四种依赖注入方式的详细介绍

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. spring有多种

  • 详解Laravel框架的依赖注入功能

    概述 任何时候,你在一个控制器类中请求一个依赖,这个服务容器负责: 1.自动地在构造函数中检测依赖关系 2.如果需要构建这个依赖关系 3.通过构造函数创建对象形成依赖关系 来看一个非常简单的例子. <?php namespace App\Http\Controllers; use App\User; use App\Repositories\UserRepository; use App\Http\Controllers\Controller; class UserController exte

  • 关于Spring的@Autowired依赖注入常见错误的总结

    做不到雨露均沾 经常会遇到,required a single bean, but 2 were found. 根据ID移除学生 DataService是个接口,其实现依赖Oracle: 现在期望把部分非核心业务从Oracle迁移到Cassandra,自然会先添加上一个新的DataService实现: @Repository @Slf4j public class CassandraDataService implements DataService{ @Override public void

  • Spring.Net IOC依赖注入原理流程解析

    一.什么是IOC.(Inversion of Control) IOC,即控制反转.不是什么技术,而是一种思想.在传统开发中,我们需要某个对象时,就手动去new一个依赖的对象.而IOC意味着将对象的控制权交给容器,而不在是直接在对象的内部控制.如何理解IOC呢?理解好IOC的关键是要明确'谁控制了谁,控制了什么?为何是反转?(有反转既有正转),哪些反面反转了.' 谁控制了谁?控制了什么?:传统程序设计,我们直接在对象内部通过new来创建对象,是程序主动去创建对象.而在ioc中,是通过一个容器去创

随机推荐