草庐IT

《Spring揭秘》-第二章- 学习记录

zc-01 2023-04-17 原文

1、IoC的理念

IoC全称为Inversion of Control,中文翻译为控制反转,同时还有一个别名叫 依赖注入DI(Dependency Injection)。大多将IoC与DI看作同等概念,也有部分观点认为 依赖注入可以看作IoC的一种实现方式。

在没有Spring的时候,当我们需要依赖某个类或服务时,一般通过new创建一个对象(或者通过ServiceLocator解决直接的依赖耦合),这些都需要主动的去获取需要的对象。

ServiceLocator是通过引入中间代理者消除对象间复杂的耦合关系,并统一管理分散的复杂耦合关系。

IoC的出现就为我们提供了更加简洁的方式,不用主动去构造对象,将“主动获取”转变为“被动接收”,下图即为IoC在整个过程中的所承担的角色

通常情况下,被注入对象会直接依赖于被依赖对象。但是在IoC的场景中,二者通过IoC Service Provider来交互,全部由IoC Service Provider统一管理。控制权由被注入对象转变为了IoC Service Provider 那里。

public class NewsProvider {
	// NewsProvider 为被注入对象
	// INewsListener和INewsPersister为被依赖对象
	private INewsListener newsListener;
	private INewsPersister newsPersister;
}

其实IoC就是这么简单!以前是需要什么自己去拿,现在是需要什么东西别人主动送过来。下图形象的说明了使用IoC模式的前后差别

2、IoC(DI)的几种依赖注入的方式

IoC模式最常用的有三种依赖注入方式,分别是构造方法注入(Constructor Injection)、setter方法注入(Setter Injection)以及接口注入(Interface Injection)。

2.1、构造方法注入

构造方法注入即 被注入对象可以通过在其构造方法中声明所依赖对象的参数列表,让IoC容器知道它所需要的依赖对象列表。由于同一个对象是不可能是被构造两次的,因此,被注入对象的构造乃至其整个生命周期,都是由IoC Service Provider来管理的。

IoC Service Provider会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。具体代码示例如下

public class NewsProvider {
	// NewsProvider 为被注入对象
	// INewsListener和INewsPersister为被依赖对象
	private INewsListener newsListener;
	private INewsPersister newsPersister;
	
	public NewsProvider(INewsListener newsListener, INewsPersister newsPersister) {
		this.newsListener = newsListener;
		this.newsPersister = newsPersister;
	}
}

构造方法注入的方式比较直观,对象被构造完成后,就进入了就绪装填,可以马上使用。

2.2、setter方法注入

对于JavaBean对象来说,通常会通过setter方法来更改相应的对象属性。所以,当前对象只要为其依赖对象所对应的属性添加setter方法,就可以通过setter方法将相应的依赖对象设置到被注入对象中。代码示例如下

public class NewsProvider {
    // NewsProvider 为被注入对象
    // INewsListener和INewsPersister为被依赖对象
    private INewsListener newsListener;
    private INewsPersister newsPersister;
    
    public void setNewsListener(INewsListener newsListener) {
        this.newsListener = newsListener;
    }
    public void setNewsPersister(INewsPersister newsPersister) {
        this.newsPersister = newsPersister;
    }
}

这样,外界就可以通过调用setNewsListener和setNewsPersister方法来注入依赖对象了。

需要注意的是,setter方法注入不像构造方法注入那样,对象构造完成后即可使用,相对而言更加宽松一些,可以在对象构造完成之后再注入。

2.3、接口注入(基本废弃)

相对前面的两种注入方式来说,接口注入会更加复杂。被注入对象如果想让IoC Service Provider为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider 最终会通过这些接口来获取被注入对象所需要的依赖对象列表。

NewsProvicer为了让IoC Service Provider 为其注入所依赖的NewsListener对象,首先需要实现一个接口 INewsListenerCallable(名称随意),这个接口会声明一个injectNewsListener方法(名称随意),重要的是该方法的参数,必须是所依赖对象的类型。这样,对应的IoC Service Provider 就可以通过这个接口方法将依赖对象注入到 被注入对象 NewsProvider 当中。代码示例如下。

public interface NewsListenerCallable {
    // 声明方法
    void injectNewsListener(INewsListener newsListener);
}

public class NewsProvider implements NewsListenerCallable{
    private INewsListener newsListener;
    @Override
    public void injectNewsListener(INewsListener newsListener) {
        this.newsListener = newsListener;
    }
}

2.3、三种注入方式的比较

  • 构造方法注入。这种注入方式的优点就是,对象在构造完成之后,就已进入就绪状态,可以马上使用。缺点就是,当依赖对象变多时,构造方法的参数列表会比较长。同时通过反射构造对象时,对相同类型的参数处理会比较困难,维护和使用上也比较麻烦。而且在Java中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能还需要引入多个构造方法,维护不便。
  • setter方法注入优点就是,在描述性上会比构造方法注入要好,同时可以被继承,允许设置默认值,而且有良好的IDE支持。缺点就是对象无法在构造完成后立马进入就绪状态。
  • 接口注入。从注入方式的使用上来说,接口注入是目前不提倡的一种方法,基本处于“退役状态”。因为需要被注入对象实现不必要的接口,带有侵入性。

综上,构造方法注入和setter注入因为其侵入性较弱,且易于理解和使用,所以是现在使用最多的注入方式;而接口注入由于其侵入性,已经不流行了。

本文由博客一文多发平台 OpenWrite 发布!

有关《Spring揭秘》-第二章- 学习记录的更多相关文章

  1. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  2. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  3. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  4. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  5. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  6. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  7. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  8. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  9. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

  10. ruby-on-rails - 在 Rails 中更高效地查找或创建多条记录 - 2

    我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr

随机推荐