Spring5应用之依赖注入

2023年 8月 22日 82.7k 0

作者简介:☕️大家好,我是Aomsir,一个爱折腾的开发者!
个人主页:Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏
当前专栏:Spring5应用专栏_Aomsir的博客

引言

之前我们已经初步了解了Spring框架的一些基本概念,今天我们将深入学习依赖注入(Dependency Injection,DI)这一重要概念,它是实现控制反转(Inversion of Control,IoC)的关键手段和思想。在Spring中,我们可以使用多种注入方式来实现依赖注入,其中包括以下几种常见的方式:Set注入、构造注入、反射注入以及基于字段的注入等等

概念详解

什么是依赖注入?

依赖注入是通过Spring容器以及配置文件,为所创建的对象(Bean)的成员变量赋值的过程

为什么需要依赖注入?

在以下示例中,我们有一个Person类,其中包含id和name两个属性。在测试代码中,我们从工厂获取了Person对象,并手动为其属性赋值。然而,这种方式引入了紧耦合,如果将来需要更改id和name的属性值,就必须修改代码、重新编译、打包和部署。这种做法并没有充分体现依赖注入的优势。依赖注入的核心概念在于使用Spring容器和配置文件来实现对象间的解耦,从而提高灵活性和可维护性

public class TestSpring {
    
    @Test
    public void test4() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = ctx.getBean("person", Person.class);

        // 通过编码为属性赋值存在耦合
        person.setId(1);
        person.setName("Aomsir");
        System.out.println("person = " + person);
    }
}

开发步骤

  • 为类成员变量提供Set/Get方法
  • 编写Spring的配置文件
  • 编写测试代码

    
        10
    
    
        Aomsir
    

简易实现原理

Spring通过底层调用对象属性对应的set方法,从而完成成员变量的赋值。这种方式也被称为set注入。通过这种机制,我们可以在配置文件中指定依赖对象,然后让Spring容器自动完成对象的创建和属性赋值,从而实现解耦和依赖注入的目标
在这里插入图片描述

Set注入详解

在Spring容器中,一个Bean的成员变量类型可能涵盖多种种类,例如Integer、String、List、HashMap,以及我们开发者自定义的类型等。这些成员变量的类型主要可以分为两种:第一种是由JDK提供的内置类型,第二种是我们开发者自己定义的类型。如下图所示:
在这里插入图片描述

JDK类型

简单的JDK类型

以下示例涵盖了对所有常见的简单JDK数据类型的测试,展示了如何在Spring中进行Set注入

@Data
public class Customer implements Serializable {
    private String name;
    private int age;
    private String[] emails;
    private Set tels;
    private List address;
    private Map qqs;
    private Properties p;
}

    
        Aomsir
    

    
        21
    

    
        
            aomsir1@apache.org
            aomsir2@apache.org
            aomsir3@apache.org
        
    

    
        
            010-1
            010-2
            010-3
        
    

    
        
            北京市
            武汉市
        
    

    
        
            
                name
                Aomsir
            
        
    

    
        
            Aomsir
        
    

复杂的JDK类型

更为复杂的JDK类型,比如Date等,用得相对较少。等知识储备足够,单独开设一个章节来深入讲解这些复杂类型的处理方式

自定义类型

下面这个示例,UserService依赖于UserDAO。UserDAO是我们自定义的类型,将会通过Set注入的方式来实现

第一种方式

在Bean内部进行嵌套,以创建另一个Bean并进行依赖注入的操作


    
        
    

第二种方式

上述第一种方式中存在一些问题。首先,会产生代码冗余的情况。其次,被注入的对象(UserDAO)可能会被多次创建,从而浪费了JVM内存资源。因此,我们可以采用以下引用的方式来进行依赖注入




    
        
    

简化写法

属性简化

上面的注入写法还是太臃肿了,可以对其简化,将之前使用的value标签替换为bean标签中的value属性,同时将之前的ref标签替换为bean标签中的ref属性。需要注意的是:value属性仅适用于8种基本类型以及String类型



    
    




    

p标签简化

另外,基于p标签,我们可以进一步简化上述的value属性设置。要使用这种方式,需要引入p命名空间标签。具体使用方式如下所示。这种方式的注意点和之前的方式相同




构造注入详解

在上述的Set注入中,Spring会调用类的Set方法,通过配置文件为成员变量赋值。而构造注入则是Spring会调用类的构造方法,在配置文件中指定参数值,从而为成员变量赋值

开发步骤

  • 类提供有参构造方法
  • 使用constructor-arg标签替换propertity标签
public class Employer {
    private Integer id;
    private String name;

    public Employer(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

    
    

重载构造

在实际开发中,我们可能会为一个类提供多个重载构造函数。如果这些构造函数参数个数不同,我们可以通过constructor-arg标签的数量来区分。而如果参数个数相同,但类型不同,我们则可以在constructor-arg标签中使用type属性来进行区分

控制反转&依赖注入

  • 控制反转(IoC):全称为Inversion of Control,即控制权的反转。它涉及到成员变量的赋值控制。这种机制的关键在于,将控制权从代码中转移到Spring容器和配置文件中。这种反转带来的最大好处之一是解耦合,底层实现基于之前章节中提到的工厂设计模式
  • 依赖注入(DI):全称为Dependency Injection,是一种思想。通过Spring的工厂和配置文件,为对象的成员变量赋值。当一个类需要另一个类时,就存在依赖关系。为了解决这种依赖,我们将另一个类作为本类的成员变量,最终通过Spring配置文件完成注入。这种机制能够更好地管理对象之间的关系,提高了灵活性和可维护性

总结

在未来的实际应用中,Set注入可能会更加常见。这主要是因为构造注入在处理重载构造函数时可能较为繁琐,容易出现参数数量和顺序的问题。另外,虽然Spring官方并未直接明确推荐使用Set注入,但实际上,其底层源码中却广泛地应用了Set注入的方式。这说明了Spring团队自己也意识到了Set注入的一些优势,并在内部使用这种方式来处理依赖关系

参考文献

  • 孙哥suns说Spring5~学不会Spring? 因为你没找对人
  • Spring官方文档

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论