Spring 依赖注入

Spring 依赖注入(Dependency Injection,DI)控制反转含义相同,它们是从两个角度描述的同一个概念。使用依赖注入可以更轻松的管理和测试应用程序。

当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring 框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建,这称为控制反转

Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例(被调用者的实例)注入给调用者,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入

依赖注入主要有两种实现方式,分别是 setter 注入(又称设值注入)构造函数注入。具体介绍如下。

1)构造函数注入

指 IoC 容器使用构造函数注入被依赖的实例。可以通过调用带参数的构造函数实现依赖注入,每个参数代表一个依赖。

2)setter 注入(设值注入)

指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 Bean 后,调用该 Bean 的 setter 方法,即可实现基于 setter 的 依赖注入DI。

在 Spring 实例化 Bean 的过程中,首先会调用默认的构造方法实例化 Bean 对象,然后通过 Java 的反射机制调用 setXxx() 方法进行属性的注入。因此,setter 注入要求 Bean 的对应类必须满足以下两点要求。

  • 必须提供一个默认的无参构造方法
  • 必须为需要注入的属性提供对应的 setter 方法

使用 setter 注入时,在 Spring 配置文件中,需要使用 <bean> 元素的子元素 <property> 为每个属性注入值。而使用构造注入时,在配置文件中,主要使用 <constructor-arg> 标签定义构造方法的参数,使用其 value 属性(或子元素)设置该参数的值。

 

构造函数注入

下面使用 <constructor-arg> 标签实现构造函数注入。

在 <constructor-arg> 标签中,包含 ref、value、type、index 等属性。

value 属性用于注入基本数据类型以及字符串类型的ref 属性用于注入已经定义好的 Bean;type 属性用来指定对应的构造函数,当构造函数有多个参数时,可以使用 index 属性指定参数的位置,index 属性值从 0 开始。

例 1

下面使用 Eclipse IDE 演示通过构造函数注入依赖项,步骤如下:

  1. 创建 SpringDemo 项目,并在 src 目录下创建 net.biancheng 包。
  2. 添加相应的 jar 包。
  3. 在 net.biancheng 包下创建 Person、Man 和 MainApp 类。
  4. 在 src 目录下创建 Spring 配置文件 Beans.xml。
  5. 运行 SpringDemo 项目。


Person 类代码如下。


复制代码
package net.biancheng;

public class Person {
    private Man man;

    public Person(Man man) {
        System.out.println("在Person的构造函数内");
        this.man = man;
    }

    public void man() {
        man.show();
    }
}
复制代码
 

Man 类代码如下。


复制代码
package net.biancheng;

public class Man {
    private String name;
    private int age;

    public Man() {
        System.out.println("在man的构造函数内");
    }

    public Man(String name, int age) {
        System.out.println("在man的有参构造函数内");
        this.name = name;
        this.age = age;
    }

    public void show() {
        System.out.println("名称:" + name + "\n年龄:" + age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
复制代码
 

Beans.xml 配置文件如下。


复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="man" class="net.biancheng.Man">
        <constructor-arg value="bianchengbang" />
        <constructor-arg value="12" type="int" />
    </bean>

    <bean id="person" class="net.biancheng.Person">
        <constructor-arg ref="man" type="java.lang.String"/>
    </bean>

</beans>
复制代码

说明:

bean man:这个提供了两个 constructor-arg,因此和构造函数【Man(String name, int age)】匹配。把两个参数,分别给构造函数的两个参数。

bean person: 提供了一个参数 constructor-arg,因此和构造函数【Person(Man man)】匹配。ref 属性用于注入已经定义好的 Bean man。

 

constructor-arg子标签:
指定创建类对象时使用哪个构造函数,每一对或每一个constructor-arg子标签配置一个参数列表中的参数值;如果不配置该子标签,则默认使用无参构造函数实例化对象。

如果需要实例化的类中有多参构造方法,那么需要用到name、type或index等属性来指定调用哪个多参构造方法和给哪个参数传值,
如果只有一个多参构造方法并且给参数传值的顺序与构造方法参数列表的顺序一致,则不需要用到这些属性。
说明:
    name属性:通过参数名找到参数列表中对应参数
    index属性:通过参数在参数列表中的索引找到参数列表中对应参数,index从0开始
    type属性:通过参数数据类型找到参数列表中对应参数
    value属性:参数值

 

MainApp 类代码如下。


复制代码
package net.biancheng;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Person person = (Person) context.getBean("person");
        person.man();
    }
}
复制代码

运行结果如下。

在man的有参构造函数内
在Person的构造函数内
名称:bianchengbang
年龄:12

 

setter注入

下面使用 <property> 标签实现 setter 注入。

在 <property> 标签中,包含 name、ref、value 等属性。name 用于指定参数名称;value 属性用于注入基本数据类型以及字符串类型的值;ref 属性用于注入已经定义好的 Bean。

例 2

在例 1 的基础上修改 Man 类的内容,代码如下。


复制代码
package net.biancheng;

public class Man {
    private String name;
    private int age;

    public Man() {
        System.out.println("在man的构造函数内");
    }

    public Man(String name, int age) {
        System.out.println("在man的有参构造函数内");
        this.name = name;
        this.age = age;
    }

    public void show() {
        System.out.println("名称:" + name + "\n年龄:" + age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
复制代码
 

Beans.xml 配置文件如下。


复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="person" class="net.biancheng.Person">
        <property name="man" ref="man" />
    </bean>

    <bean id="man" class="net.biancheng.Man">
        <property name="name" value="bianchengbang" />
        <property name="age" value="12" />
    </bean>

</beans>
复制代码

运行结果如下。

在man的构造函数内
在setMan方法内
名称:bianchengbang
年龄:12

 

REF:

http://c.biancheng.net/spring/di.html

posted @   emanlee  阅读(167)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2019-08-16 为Endnote中的期刊名称添加缩写期刊名
2017-08-16 qvalue: Check that you have valid p-values or use a different range of lambda
2014-08-16 mysql 字符串函数
2011-08-16 WinRAR命令行参数
2011-08-16 水平集方法 level set method
2011-08-16 基底膜(basement membrane, BM)
2011-08-16 肿瘤基础知识
点击右上角即可分享
微信分享提示