Spring的核心机制:依赖注入(Dependency Injection)

ESXI 8.0.3 ubuntu 24.04 直通显卡P40 手把手,一步步教你直通GPU,ESXI 8.0.3 ubuntu 24.04 直通显卡P40 阅读详情

本文摘自:李刚 著 《轻量级 Java EE企业应用实战 Struts2+Spring+hibernate整合开发》

 

 

        依赖注入(Dependency Injection) 是时下的"流行语",也是目前最优秀的解耦方式。使用依赖注入时,J2EE中的各种组件不需要以硬编码方式耦合在一起,甚至无须使用工厂模式。当某个Java实例需要其他Java实例时,系统和自动提供所需要的实例,无需程序显式获取。

        依赖注入是Spring 的核心机制,可以使Spring 的bean 以配置文件组织在一起,而不是以硬编码的方式耦合在一起。

 

一. 理解依赖注入

 

        因为某些历史原因,依赖注入还有一种称呼:控制反转(Inversion of Control)。

        不管是依赖注入,还是控制反转,其含义完全相同。当某个Java 实例(调用者)需要另一个Java 实例(被调用者)时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。而在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,通常由Spring 容器来完成,然后注入调用者,因此称为控制反转,也称为依赖注入。

        不管是依赖注入,还是控制反转,都说明Spring 采用动态及灵活的方式来管理各种对象,使对象与对象之间的具体实现互相透明。

        为了更好地理解依赖注入,笔者建议参考人类社会的发展,看如下问题在各种社会形态里如何解决:一个人(Java 实例,调用者)需要一把斧子(Java 实例,被调用者)。

        在"原始社会"里,几乎没有社会分工。需要斧子的人(调用者)只能自己去磨一把斧子(被调用者)。对应的情形为:Java 程序里的调用者自己创建被调用者。

        进入"工业社会"后,随着工厂的出现,斧子不再由普通人完成,而在工厂里被生产出来。此时需要斧子的人(调用者)只需找到工厂,购买斧子,无须关心斧子的制造过程。对应简单工厂设计模式:调用者只需要定位工厂,无须管理被调用者具体的实现。

        进入"共产主义"社会后,需要斧子的人甚至无须定位工厂,"坐等"社会提供即可。调用者无须关心被调用者的实现,无须理会工厂,等待Spring 依赖注入即可。

        在第一种情况下,由Java 实例的调用者创建被调用的Java 实例,调用者直接使用new 关键宇创建被调用者实例,其程序高度藕合,效率低下。在实际应用中极少使用这
种方式。

        在第二种情况下,调用者无须关心被调用者的具体实现过程,只需要找到符合某种标准(接口)的实例即可使用。此时调用的代码面向接口编程,可以让调用者和被调用者解耦,这也是工厂模式被大量使用的原因。但调用者需要自己定位工厂,使调用者与工厂耦合在一起。

        第三种情况,是最理想的情况,程序完全无须理会被调用者的实现,也无须定位工厂,是最好的解耦方式。实例之间的依赖关系由容器提供。

        所谓依赖注入,是指在程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring 的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO 之间依赖关系的管理。

        依赖注入方式通常有两种:

        设值注入和构造注入

 

二. 设值注入

 

        设值注入是指通过setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring 的依赖注入里大量使用。

        Person接口的代码如下:

package ppp;
public interface Person {
	//Person接口里定义一个使用斧子的方法
	public void useAxe();
}

       Axe接口的代码如下:

package ppp;
//定义一个Axe接口
public interface Axe {
	//Axe接口里有一个砍的方法
	public String chop();
}

        Person接口的实现类如下:

package ppp;
//Chinese实现Person接口
public class Chinese implements Person{
	//面向Axe接口编程,而不是具体的实现类
	private Axe axe;
	public Chinese(){
	}
	public setAxe(Axe axe)
	{
		this.axe = axe;
	}
	//实现Person接口的useAxe方法
	public void useAxe(){
		System.out.println(axe.chop());
	}
}

        Axe接口的第一个实现类的代码如下:

package ppp;
public class StoneAxe implements Axe{
	//默认构造器
	public StoneAxe(){	}
	//实现Axe接口的chop方法
	public String chop(){
		return "石斧砍柴好慢";
	}
}

        下面采用Spring 的配置文件将Person实例和Axe实例组织在一起。配置文件如下所示:


        从配置文件中可以看到Spring 管理bean 的灵巧性。bean 与bean 之间的依赖关系被放在配置文件里组织,而不是写在代码里。通过配置文件的指定,Spring 能精确地为每
个bean 注入属性。因此,配置文件里bean 的class 元素不能是接口,而必须是真正的实现类。

        另外, Spring 会自动接管每个bean 定义里的property 元素定义。Spring 会在执行无参数的构造器后,创建默认的bean 实例,并调用对应的setter 方法为程序注入属性值。在这里, property 定义的属性值将不再由该bean 来主动创建和管理,而是接收Spring 的注入。

         每个bean 的id 属性是该bean 的唯一标识,程序通过id 属性来访问bean , bean 与bean 的依赖关系也通过id 属性关联。

         以下是主程序部分:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class BeanTest {
	public static void main(String[] args) throws FileNotFoundException, SQLException {
	    //因为是独立的应用程序,所以显示实例化Spring上下文
		ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
		//通过Person Bean的id来获取bean的实例,面向接口编程,
		//因此此处强制类型转换为接口类型
		Person p = (Person)ctx.getBean("chinese");
		//直接执行Person的useAxe方法
		p.useAxe();
      }
}

       程序执行结果是:石斧砍柴好慢

       当主程序调用Person的useAxe()方法时,该方法的方法体内需要使用Axe 的实例,但程序里没有任何地方将特定的Person实例和Axe 实例耦合在一起。或者说程序里没有为Person实例传入Axe的实例,而Axe实例由Spring在运行期间动态注入。Person 实例既不需要了解Axe 实例的具体实现,也无须了解Axe 的创建过程。程序在运行到需要Axe 实例时,由Spring 创建Axe 实例,然后注入给需要Axe 实例的调用者。因此,当Person 实例运行到需要Axe 实例的地方时,自然就产生了Axe 实例,用来供Person 实例使用。

       如果需要改写Axe 的实现类,或者说提供另一个实现类给Person 实例使用时。Person接口、Chinese 类都无须改变,只需提供另一个Axe 的实现类,然后对配置文件进行简单的修改即可。

       Axe 的另一个实现类如下:

package ppp;
public class SteelAxe implements Axe{
	//默认构造器
	public SteelAxe(){}
	//实现Axe接口的chop方法
	public String chop(){
		return "钢斧砍柴真快";
	}
}

       修改原来的Spring配置文件

        再次运行程序,此时显示:钢斧砍柴真快

        由此可看出, Person 与Axe 之间没有任何代码藕合关系, bean 与bean 之间的依赖关系由Spring 管理。采用以setter 方法为目标bean 注入属性的方式我们称为设值注入。

        通过配置文件动态管理,可使对象与对象之间的依赖关系从代码里分离出来,业务对象的更换也变得相当简单。

 

三. 构造注入

 

        所谓构造注入,指通过构造函数来完成依赖关系的设定,而不是通过setter 方法。对前面代码Chinese 类作简单的修改,修改后的代码如下:

package ppp;
//Chinese实现Person接口
public class Chinese implements Person{
	//面向Axe接口编程,而不是具体的实现类
	private Axe axe;
	public Chinese(){
	}
	//构造注入所需的带参数的构造器
	public Chinese(Axe axe){
		this.axe = axe;
	}
         //实现Person接口的useAxe方法
	public void useAxe(){
		System.out.println(axe.chop());
	}
}

        此时无须Chinese 类里的setAxe 方法,在构造Person 实例时, Spring 为Person 实例注入所依赖的Axe 实例。

        构造注入的配置文件也需作简单的修改,修改后的配置文件如下:


        由此可看出,执行效果与使用steelAxe 设值注入时的执行效果完全相同。区别在于创建Person 实例中Axe 属性的时机不同一-设值注入是先创建一个默认的bean 实例,然后调用对应的setter方法注入依赖关系;而构造注入则在创建bean 实例时,已经完成了依赖关系的注入。

 

四. 两种注入方式的对比

 

        Spring 同时支持两种依赖注入方式:设值注入和构造注入。这两种注入方式各有其优、缺点。

         1   设值注入的优点

        设值注入与传统的JavaBean 的写法更相似,程序开发人员更容易了解,接受。通过setter 方法设定依赖关系显得更加直观、自然。对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。因为Spring 在创建bean 实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。尤其是在某些属性可选的情况下,多参数的构造器更加笨重。

         2  构造注入的优点

        (1) 可以在构造器中决定依赖关系的注入顺序。例如,组件中其他依赖关系的注入,常常需要依赖于Datasource 的注入。采用构造注入时,可以在代码中清晰地决定注入顺序,优先依赖的优先注入。

        (2)对于依赖关系无须变化的bean ,构造注入更有用处。因为没有setter 方法,所有的依赖关系全部在构造器内设定。因此,无须担心后续的代码对依赖关系产生破坏。

        (3)依赖关系只能在构造器中设定,因为只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。

        建议采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设值注入。

 

Isaac Lab强化学习实战:用SO-ARM101机械臂实现抓取任务(附B站视频教程) 本文详细介绍了如何使用Isaac Lab强化学习框架,在SO-ARM101机械臂上实现抓取任务的完整实战流程。内容涵盖从环境搭建、奖励函数设计、训练调参到模型部署的各个环节,并分享了Sim-to-Real迁移的关键技巧,旨在帮助开发者高效完成机器人强化学习项目。 阅读详情

相关推荐

Bartender 2021破解版安装教程:手把手教你从下载到激活(附详细步骤图)

本文详细介绍了BarTender 2021专业版的安装与高效应用指南,从基础配置到高级条码设计,帮助用户快速掌握标签设计与打印技术。内容涵盖安装步骤、标签模板创建、数据连接与批量打印技巧,以及高级功能如安全策略与自动化集成,适合零售、物流、制造等行业用户提升工作效率。

p4q5r6s7t的博客 2661

.Net 5 DependencyInjection 依赖注入

.Net DependencyInjection 依赖注入 服务注册 不由服务容器创建的服务 服务获取 生命周期 作用域验证 构造函数注入行为 Asp.Net Core,注入 Startup 的服务 使用扩展方法注册服务组 从 main 调用服务 依赖注入(Dependency Injection)简称DI,DI实现了控制反转(Inversion of Control,Ioc),遵循了依赖倒置原则, DI实现解耦、不需要手动去获取或创建依赖的对象 控制反转:由容器帮我们控制对象的创建和依赖对象的注入 正.

Globalizationa的博客 1190

metaRTC嵌入式webrtc编译指南

metaRTC编译支持qmake和cmake,qmake使用QT最为方便,新版本新增了cmake支持。 ...

metaRTC的博客 9518

Spring Dependency Injection - 依赖注入使用技巧

就不知道是怎么注入的了。场景:是一个案例中使用到了 @ConditionalOnProperty 注解,我们也可以自定义一个 Conditional 的实现类,之后把这个实现类配置到需要实例化的对象上面,通过 matches 匹配条件方法的实现,决定是否实例化。场景:模拟创建 createTopic,入参的对象为注入的操作,@Qualifier 注解可以指定要注入哪个名字的对象。用途:当我们为一组接口提供实现类,并需要提供默认的注入的时候,就可以使用 @Primary 注解来限定首选注入项。

优快云_LiMingfly的博客 1084

ORCAD 层次化原理图使用TCL获取位号的方法

orcad tcl 获取occurrence位号的方法。

m0_46675718的博客 1134

OBYC自动科目确定整理

WGI是用来重估发货的,通过比较发货时的价格和最新计算的价格,以此将所有差异过账到分配给此事务码的总账科目。是工厂还是公司,一般项目中都是使用工厂,使用工厂的意思就是物料在每个工厂下有一个价格,如果使用公司,则一个公司下的所有工厂都使用一个价格。如果该物料用的是移动平均价,那么该库存依然还存在的情况下,这个价格差异会过账到存货科目上而不会过账到存货的价格差异科目上。用于确定存货评估过账的存货冲抵科目。事务码WGR是用来重估工厂收货的,根据 计算出来的价格差异,把库存的调整过账分配给这个事务码中的总账科目。

nopicture的博客 349

依赖注入(Dependency Injection)框架是如何实现的

DI容器的核心功能一般有三个:配置解析、对象创建和对象生命周期管理

Hopefully Sky的博客 3415

使用 Pfam 和 InterProScan 进行蛋白质家族和功能域的分析

本文介绍了使用Pfam和InterProScan进行蛋白质家族与功能域分析的方法。主要内容包括:1) Pfam数据库的本地化使用,通过hmmscan工具比对Pfam-A.hmm数据库,并提供了批量处理Python脚本;2) InterProScan的安装配置与命令行参数详解,支持多数据库整合分析;3) 补充介绍了基于curl的Uniprot在线查询方法。文章提供了从软件安装到实战分析的完整流程,适用于本地化、批量化蛋白质功能注释需求,特别是无网络环境或大规模数据分析场景,适合不同水平的生物信息学用户。

Protein Designer的博客 1922

Spring Framework学习之路(10)--- 依赖注入

Spring 依赖注入

极乐净土 478

从 SEGW 到 SADL 的那根线,彻底理解 OData Data Source Mapping

本文摘要(150字): 在SAP Gateway的SADL型OData服务开发中,"Map to Data Source"是关键配置环节。与传统RFC映射不同,SADL映射不是针对单个CRUDQ操作,而是建立OData模型与SADL业务实体间的完整语义对应关系。通过属性映射和关联映射,系统能自动处理数据获取和导航请求。映射编辑器支持三种模式:属性映射处理字段对应,关联映射处理模型间关系,动作映射处理业务操作。映射的本质是建立语义翻译表,决定了后续OData请求如何转化为后端业务实体访问,而非简单的字段重命名

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 61

【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析

【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析

|~~~热爱生活、努力学习的小伙汁~~~| 2112

深度理解依赖注入(Dependence Injection)

前面的话:提到依赖注入,大家都会想到老马那篇经典的文章。其实,本文就是相当于对那篇文章的解读。所以,如果您对原文已经有了非常深刻的理解,完全不需要再看此文;但是,如果您和笔者一样,以前曾经看过,似乎看懂了,但似乎又没抓到什么要领,不妨看看笔者这个解读,也许对您理解原文有一定帮助。 1.依赖在哪里 老马举了一个小例子,是开发一个电影列举器(MovieList),这个电影列举器...

Zy0414的博客 805

结构光之相移法+多频外差的数学原理推导

‍论文:基于数字光栅投影的结构光三维测量技术与系统研究 [博]作者:李中伟 华中科技大学 2007功能:相移法:多频外差(三频N步相移法)01 相移法图1 待写入投影仪的理想N步相移条纹通常对于 步相移来说,生成第 幅条纹图像(如图1所示)的公式如下:402 Payment Required其中::背景光强:调制强度:像素点横向坐标:相移值图2 相机拍摄到的实际 N ......

3D视觉工坊 1190

Spring的核心机制依赖注入简介

   Spring能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当

文艺地工作着 464

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

spring依赖注入的方式

Spring 能有效地组织 J2EE 应用各层的对象。不管是控制层的 Action 对象,还是业务层的 Service 对象,还是持久层的 DAO 对象,都可在 Spring 的管理下有机地协调、运行。 Spring 将各层的对象以松耦合的方式组织在一起, Action 对象无须关心 Service 对象的具体实现, Service 对象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当

Saltwater_leo的专栏 518

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Spring(二) 依赖注入

1. Spring的核心机制:依赖注入(Dependency Injection)Spring框架的核心功能有2个:(1) Spring容器作为超级大工厂,负责创建、管理所有java对象,这些java对象被称为Bean。(2) Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系。依赖注入是种优秀的解耦方式...

weixin_34360651的博客 96

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

总结: 十分钟快速理解 Spring IoC 控制反转

       Ioc 全名Inversion of Control ,翻译过来就是控制反转的意思.上一篇文章中,我们学习了依赖注入.       Spring能有效地组织J2EE应用各层的对象.不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO层对象,都可在Spring的管理下有机的协调,运行.Spring将各层的对象以松耦合的方式组合在一起,Action对象无须关...

李俊标的博客 3764

Spring 原理的基本解释

Spring能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少

quechao123的专栏 935

Spring框架:在Ioc容器中配置Bean

IOC&DI概述 配置Bean: 配置形式:基于XML文件的方式,基于注解的方式 Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean IOC容器BeanFactory&ApplicationContext概述 依赖注入的方式:属性注入,构造器注入 注入属性值细节 自动转配 bean之间的关系:继承;依赖...

yorkmass 463

Spring学习—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)

一、思想理解    Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系

salonzhou的专栏 687

spring mysql注入_Spring学习笔记(5)----依赖注入的简单实现

Spring的核心机制是依赖注入。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用...

weixin_42462007的博客 217

Spring学习

一 spring的IoC容器 Ioc 控制反转 inversion of control DI 依赖注入 Dependency injection 控制反转理解: 类的生成不在通过手动new,而是将其控制权交给spring管理。依赖注入则是对象或简单类型数据作为属性注入到另一个对象中。 IOC 他的反转,反转在让事必躬亲转变为享受服务(因为有依赖注入)。 依赖注入的方式_构造方...

weixin_34204057的博客 82

Spring学习3—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)

一、思想理解    Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。...

weixin_33757911的博客 84

Spring初识

从上学期开始决心开始学习Spring,自己总是利用不好时间,到处瞎忙,结果浪费了好多时间。想着利用暑假的时间,专心看会儿书。最初我在Spring官网下载jar包的时候,忙会儿了半天愣是没找到下载的链接,瞬间觉得学Spring好难,莫名的抵触心理开始泛滥,无奈只好强抱度娘。这是我找到的链接。 教您怎么从spring 官网下载参考文档 附上小图: Spring官网下载 嘿嘿,其实好简单哦,可是人家...

weixin_33730836的博客 85

spring的ioc原理

spring ioc原理(看完后大家可以自己写一个spring)

s2940086379的博客 401

Spring IOC、DI 注解和Spring MVC 注解使用

Spring IOC、DI 注解和Spring MVC 注解使用

m0_46478235的博客 238
上一篇: 关于Spring的异常:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
下一篇: Spring容器和被管理的Bean
IMFuckingHigh
博客等级 码龄18年 85粉丝 21原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值