栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

Spring依赖注入和控制反转

Java 更新时间:发布时间: 百科书网 趣学号

学习依赖注入和控制反转的概念,然后借助代码示例了解 Spring 框架如何支持它们。

控制反转

在我们开始做任何事情之前,让我们先了解一下什么是控制反转。

控制反转是面向对象编程中使用的术语,通过该术语,对象或对象集的控制权被赋予框架或由框架提供的容器。

虽然上面的图片是幽默的,但它描述了什么是控制反转。如果我们将人类视为软件组件或服务,他们的目的是执行诸如起床、开会或支付账单等行为。对于其他事情,例如跟踪会议,设置警报或提醒人们使用电话或任何智能设备。

什么是依赖?

一个应用程序由多个类组成。通常,每个类都应该有自己的专门职责。这导致我们的类与不同的类集成以完成某些功能。当A类调用B类的方法时,A类依赖B类。

紧耦合对象

了解依赖项如何导致紧耦合对象问题。请参阅下面的代码。

这是一个FileUploadService抓取文件,检查文件是否具有预期扩展名之一并要求 aFileStorageService存储文件。

公共类 FileUploadService {
 
    private List validFiles = Arrays.asList("xls", "doc"."txt", "ppt");
    私有 FileStorageService 服务 = 新 AzureBlobStorageService();
 
    公共文件上传服务(){}
 
    //
    // 其他方法
    //
}

在上面的代码中,我们使用Program to Interface原理来实例化FileStorageService. 但是,相应的实现仍然是在类中硬编码的。也是validFiles硬编码的。它们都导致了紧耦合对象。

松散耦合对象

让我们稍微更新FileUploadService一下,我们将得到松散耦合的对象。

public class FileUploadService {
 
    private List validFiles;
    private FileStorageService service;
    
    public FileUploadService(List validFiles, FileStorageService service){
        this.validFiles = validFiles;
        this.service = service;
    }
}
 
class User {
    public static void main(String[] ar) {
        List validFiles = Arrays.asList("xls", "ppt", "doc");
        FileStorageService service = new AzureBlobStorageService();
        
        FileUploadService fileUploadService = new FileUploadService(validFiles, service);
    }
}
  • 第 3 行: 变量已声明但未初始化。没有硬编码值。
  • 第 4 行: 仅对FileStorageService类型的引用。没有附加实现。
  • 第 6 行: 所有参数构造函数。

让我们看看User课堂上发生了什么,实际上是FileUploadService.

  • 第 17 行: FileUploadService通过将所有必需的参数传递给构造函数来创建实例。

依赖注入

我们刚刚所做的称为依赖注入。

依赖注入是面向对象编程中使用的一个术语,通过它,对象将专注于执行分配的功能并利用其他对象。对象不会处理必要的配置和初始化。但是,对象将提供一种通过字段分配、字段设置器或构造函数来初始化它们及其依赖关系的方法。这样,外部实体可以初始化事物而不是实际对象。

在基于 Spring 的应用程序中,Inversion of Control Container(IoC 容器)执行依赖注入。我们将在接下来的部分中看到这一点。首先,让我们看看为什么我们甚至需要这样一个容器。

为什么我们需要 IoC 容器?

我已经修改了前面的代码示例。它现在是一个ResumeUploaderService. ACandidate可以将其简历分享给ResumeUploaderService. 该服务应在验证扩展后,将其共享给ResumeStorageService. 根据组织当前的策略,简历被存储在文件系统的机密文件夹中(by

public class ResumeUploaderService {
 
    private List validFiles;
    private ResumeStorageService service;
 
    public ResumeUploaderService(List validFiles, ResumeStorageService service) {
        this.validFiles = validFiles;
        this.service = service;
    }
}
 
 
class Candidate {
    public static void main(String[] ar) {
        List validFiles = Arrays.asList("pdf", "doc");
 
        String filePath = "/Users/app/confidential/storage/resume";
        ResumeStorageService service = new FileSystemResumeStorageService(filePath);
 
        ResumeUploaderService fileUploadService = new ResumeUploaderService(validFiles, service);
    }
}

第 4 行:ResumeUploaderService 具有对ResumeStorageService.

第 6 行:接受并设置ResumeStorageService.

要上传简历,Candidate必须实例化ResumeUploaderService并传递简历。但随着这一切dependency injection,候选人的工作变得困难。候选者不仅要实例化ResumeUploaderService,还要实例化ResumeStorageService. 因为,没有后者,前者就无法实例化。

  • 第 17 行: 候选人决定将简历存储在哪里(我知道……这很有趣!!)
  • 第 18 行: 候选人决定是否使用FileSystemResumeStorageService或AzureBlobStorageService。
  • 第 20 行: 最后,候选实例化ResumeUploaderService.

以下是上面的重要问题

  • 消费者知道的太多了。
  • 消费者,而不是使用服务,也初始化它。
  • 消费者不应该担心如何ResumeUploaderService完成它的工作(缺乏抽象)。
  • 作为最终消费者,我们必须了解所有内容,并且必须初始化系统中的所有内容。

这清楚地表明,我们需要一些可以处理所有配置和初始化的东西。某些东西,其唯一职责是管理初始化。

控制容器反转(IoC 容器)

Spring 提供了一个 IoC Container 来解决这个问题。这个容器实例化了所有的对象,同时它也解决了它们的依赖关系。该类ApplicationContext代表 Spring IOC 容器。应用程序上下文负责实例化、配置和连接 bean。

请记住,Bean 只不过是在 Spring 的应用程序上下文中注册的 Java 对象。

要配置、实例化或编写 bean,应用程序上下文需要一些指令。这些指令可以以 XML 配置、Java 注释或代码的形式提供。

Spring 依赖注入

在Spring中,每个对象都是一个 bean。每个对象都有一个id或name。ApplicationContext跟踪所有这些 bes 和 id 。当消费者请求 bean 时,应用程序上下文返回 bean 的一个实例。查看下面的代码以详细了解 bean 创建和布线。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
@Component("resumeStorageService")
public class FileSystemResumeStorageService implements ResumeStorageService {
 
    @Value("${resume.storage.path}")
    private String storagePath;             // Storage path assigned based on properties file
 
    //
    // Skipped methods
    //
}
  • 第 4 行: 告诉 Spring 将此类注册为 Bean 并通过给定名称识别它。如果未提供名称,则将类名视为标识符。
  • 第 8 行: 存储路径现在直接从属性文件中注入。消费者无需通过它。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
 
@Component
public class ResumeUploaderService {
 
    @Autowired
    @Qualifier("resumeStorageService")
    private ResumeStorageService storageService;
 
 
    public ResumeUploaderService(ResumeStorageService storageService) {
        this.storageService = storageService;
    }
 
    //
    // Skipped methods
    //
}
  • 第 5 行: 将类声明为 Spring Bean,将类名声明为标识符。
  • 第 10 行: 告诉 spring 自动连接ResumeStorageService由"resumeStorageService".

如果我们想附加一个不同的实现,ResumeStorageService则ResumeUploaderService根本不会改变。

import org.springframework.beans.factory.annotation.Autowired;
 
public class Candidate {
    @Autowired private ResumeUploaderService resumeUploaderService;
 
    public void upload(Byte[] resume) {
        resumeUploaderService.uploadResume(resume);
    }
}
  • 第 4 行: 要求 Spring 分配resumeUploaderService.

一切都那么干净和专注。没有类正在初始化另一个类或为另一个类设置任何配置。一切都由 Spring 的Inversion of Control Container (IoC Container)管理。

概括

您已经完成了Spring 依赖注入和控制反转指南。您了解了什么是依赖关系以及类如何紧密耦合或松散耦合。我们了解了面向对象编程中的依赖注入和控制反转的概念。您还了解到Spring的控制反转容器(IoC 容器)管理我们 Spring 应用程序中的所有依赖注入。
 

给大家整理了今年来最经典的面试真题100道,每个题目都有详细的解答,收集了java基础、RabbitMQ,微服务、MySQL数据库、Java并发、JVM,Redis、设计模式,Spring / Spring MVC,等专题的经典面试真题,和详细分析。

数据库篇

  1. 事务四大特性(ACID)原子性、一致性、隔离性、持久性?
  2. 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?
  3. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
  4. MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?
  5. MySQL B+Tree 索引和 Hash 索引的区别?
  6. sql 查询语句确定创建哪种类型的索引,如何优化查询
  7. 有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
  8. 数据库的读写分离、主从复制,主从复制分析的 7 个问题?
  9. MySQL 都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
  10. MySQL 高并发环境解决方案?
这些问题都是抽取了部分发出来,答案解析和知识点都整理在这个近500页的Java学习笔记文档里了,详细内容有很多,为了不影响阅读,可看整理的《Java架构进阶笔记》,见文末

Spring篇

  1. Spring IoC、AOP 原理
  2. Spring Bean 生命周期
  3. Spring Bean 注入是如何解决循环依赖问题的
  4. 怎样用注解的方式配置 Spring?
  5. Spring 事务为何失效了
  6. SpringMVC 的流程?
  7. Springmvc 的优点:
  8. Spring 通知类型使用场景分别有哪些?
  9. IoC 控制反转设计原理?
  10. Spring 如何处理线程并发问题?

JVM篇

  1. Java 类加载过程?
  2. 描述一下 JVM 加载 Class 文件的原理机制?
  3. 简述 Java 垃圾回收机制。
  4. 什么是类加载器,类加载器有哪些?
  5. 如何判断一个对象是否存活?(或者 GC 对象的判定方法)
  6. 垃圾回收的优点和原理。并考虑 2 种回收机制。
  7. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收
  8. Java 中会存在内存泄漏吗,请简单描述。
  9. 简述 Java 内存分配与回收策率以及 Minor GC 和 Major GC。
  10. Java 中垃圾收集的方法有哪些?

Java并发篇

  1. Synchronized 用过吗,其原理是什么?
  2. 为什么说 Synchronized 是非公平锁?
  3. 为什么说 Synchronized 是一个悲观锁?乐观锁的实现原理又是什么?什么是 CAS,它有
  4. 请尽可能详尽地对比下 Synchronized 和 ReentrantLock 的异同。
  5. 谈谈 ReadWriteLock 和 StampedLock。
  6. 如何让 Java 的线程彼此同步?你了解过哪些同步器?请分别介绍下。
  7. 线程池中的线程是怎么创建的?是一开始就随着线程池的启动创建好的吗?
  8. 提到可以通过配置不同参数创建出不同的线程池,那么 Java 中默认实现好的线程池又有哪些呢?请比
  9. 如何在 Java 线程池中提交线程?
  10. 请谈谈 volatile 有什么特点,为什么它能保证变量对所有线程的可见性?
这些问题都是抽取了部分发出来,答案解析和知识点都整理在这个近500页的Java学习笔记文档里了,详细内容有很多,为了不影响阅读,可看整理的《Java架构进阶笔记》,文末有获取方式

Redis缓存篇

  1. 什么是 Redis 事务?原理是什么?
  2. 请介绍一下 Redis 的数据类型 SortedSet(zset)以及底层实现机制?
  3. Redis 常用的命令有哪些?
  4. 什么是缓存穿透?怎么解决?
  5. 什么是缓存雪崩? 怎么解决?
  6. 请介绍几个可能导致 Redis 阻塞的原因
  7. 缓存的更新策略有几种?分别有什么注意事项?
  8. Redis 为什么设计成单线程的?
  9. Redis 持久化机制 AOF 和 RDB 有哪些不同之处?
  10. Redis 缓存失效策略有哪些?

RabbitMQ篇

  1. RabbitMQ 的使用场景有哪些?
  2. RabbitMQ 有哪些重要的角色?
  3. RabbitMQ 有哪些重要的组件?
  4. RabbitMQ 的消息是怎么发送的?
  5. RabbitMQ 怎么保证消息的稳定性?
  6. RabbitMQ 怎么避免消息丢失?
  7. 要保证消息持久化成功的条件有哪些?
  8. RabbitMQ 有几种广播类型?
  9. RabbitMQ 怎么实现延迟消息队列?
  10. RabbitMQ 集群中唯一一个磁盘节点崩溃了会发生什么情况?

Java集合篇

  1. ArrayList 和 Vector 的区别
  2. 说说 ArrayList,Vector, LinkedList 的存储性能和特性
  3. 快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?
  4. hashmap 的数据结构。
  5. HashMap 的工作原理是什么?
  6. Hashmap 什么时候进行扩容呢?
  7. HashSet 和 TreeSet 有什么区别?
  8. HashSet 的底层实现是什么?
  9. LinkedHashMap 的实现原理?
  10. Collection 和 Collections 的区别。

微服务篇

  1. 使用Spring Cloud有什么优势?
  2. 服务注册和发现是什么意思?Spring Cloud如何实现?
  3. 负载平衡的意义什么?
  4. 什么是Hystrix?它如何实现容错?
  5. 什么是Hystrix断路器?我们需要它吗?
  6. 什么是Netflix Feign?它的优点是什么?
  7. Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
  8. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
  9. Spring Boot中的监视器是什么?
  10. 什么是Swagger?你用Spring Boot实现了它吗?

Zookeeper篇

  1. zk的命名服务(文件系统)
  2. zk的配置管理(文件系统、通知机制)
  3. Zookeeper集群管理(文件系统、通知机制)
  4. Zookeeper分布式锁(文件系统、通知机制)
  5. 获取分布式锁的流程
  6. Zookeeper队列管理(文件系统、通知机制)
  7. Zookeeper数据复制
  8. Zookeeper工作原理
  9. zookeeper是如何保证事务的顺序一致性的?
  10. Zookeeper 下 Server工作状态

解决方案篇

  1. API接口安全设计
  2. 秒杀系统设计思路
  3. 分布式事务解决方案
  4. SSO单点登录方案
  5. Redis缓存和MySQL数据一致性方案详解
  6. 分库分表设计
  7. 缓存雪崩,穿透,击穿解决方案
最后

对于这些问题我都整理了答案,记录在这个Java学习笔记里,这份笔记包括了Spring,JVM,java基础,Java集合,Java并发编程,微服务,网络,Kafka,分布式,Redis,大厂面试解决方案,分布式事务,设计模式,算法,数据结构,MySQL等

详细内容有很多,为了不影响阅读,可看整理的《Java架构进阶笔记》,可关注下方公众!免费获取!

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/852408.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号