IoC设计模式详解:控制反转的核心思想
前言:在软件开发中,设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转(Inversion of Control,IoC) 作为一种设计模式,通过让程序的控制流和对象管理反转,从而使得代码的解耦性和可维护性大大提高。
学习Spring,其中一个核心——Spring IoC容器,则是这一模式在Spring框架中的具体实现。
一、IoC简介
IoC(控制反转)是一种设计模式(原则),核心思想是将对象的创建、初始化和依赖关系的管理从程序中反转出来,交由外部容器(例如 Spring)来负责。
也就是说,程序不再控制对象的创建和生命周期,而是通过外部容器来进行管理,这样可以实现更高的解耦和灵活性。
控制反转显然是一个抽象的概念,举一个鲜明的例子来说明:
在现实生活中,人们要用到一样东西的时候,第一反应就是去找到这件东西,比如想喝新鲜橙汁,在没有饮品店的日子里,最直观的做法就是:买果汁机、买橙子,然后准备开水。值得注意的是:这些都是你自己 “主动”创造的过程,也就是说一杯橙汁需要你自己创造。
然而到了今时今日,由于饮品店的盛行,当我们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,通过电话等渠道描述你的需要、地址、联系方式等,下订单等待,过一会儿就会有人送来橙汁了。
请注意你并没有“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也完全达到了你的要求,甚至比你创造的要好上那么一些。
所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
二、发展
IoC(Inversion of Control,控制反转)设计原则的发展历程反映了软件工程领域中对解耦合、模块化和可测试性的不断追求。以下是IoC设计理念从萌芽到成熟的主要发展阶段:
1. 早期探索与概念形成
- 20世纪80年代至90年代初:在面向对象编程(OOP)逐渐普及的背景下,开发者开始意识到直接在代码中创建和管理依赖会导致高度耦合的问题。此时,一些先驱者开始思考如何将这种控制权转移给外部组件或框架。
- MVC模式:Model-View-Controller架构是最早体现IoC思想的设计模式之一,它通过分离关注点来实现一定程度上的解耦。
2. IoC概念的正式提出
-
1996年:Michael Mattson在他的论文《Object-Oriented Frameworks: A Survey》中首次使用了“控制反转”这个术语,用来描述框架如何接管应用程序的主控流程。
-
2004年:Martin Fowler在其文章《Inversion of Control Containers and the Dependency Injection pattern》中详细阐述了IoC的概念,并引入了“依赖注入”(Dependency Injection, DI)这一术语作为IoC的具体实现方式。这篇文章极大地推动了DI模式的流行。
”软件开发教父“—Martin Fowler
3. 框架与工具的支持
- Spring框架的崛起:Spring于2004年发布,迅速成为Java企业级应用开发中最受欢迎的框架之一。Spring的核心特性之一就是其强大的IoC容器,它不仅实现了基本的DI功能,还提供了丰富的配置选项和生命周期管理机制。
- 其他框架:除了Spring,还有许多其他框架也采用了IoC/DI模式,如PicoContainer、Guice(Google推出的轻量级Java依赖注入框架)、以及.NET平台下的Ninject等。这些框架进一步促进了IoC理念在不同编程语言和技术栈中的传播。
4. 扩展与深化
- AOP集成:随着面向切面编程(Aspect-Oriented Programming, AOP)的发展,IoC容器开始支持AOP特性,允许开发者以声明式的方式定义横切关注点(如日志记录、事务管理),从而进一步减少了代码中的重复劳动。
- 事件驱动架构:现代应用越来越多地采用事件驱动的方式进行组件间通信,而IoC容器提供的事件发布/订阅机制正好满足了这一需求,使得系统更加灵活且易于扩展。
- 微服务架构:在微服务架构中,每个服务都是独立部署的单元,它们之间的交互通常通过API网关或消息队列完成。在这种情况下,IoC容器的作用变得更加重要,因为它可以帮助管理和协调各个服务之间的依赖关系。
5. 当前趋势与发展
- 函数式编程与响应式编程:随着函数式编程语言(如Scala、Clojure)以及响应式编程模型(Reactive Programming)的兴起,IoC/DI模式也在不断演进,以适应新的编程范式。例如,在响应式流处理中,依赖注入可以用于简化异步操作和背压管理。
- 云原生应用:在云环境中,服务发现、配置管理等功能变得至关重要。IoC容器可以通过集成服务注册中心(如Eureka、Consul)和分布式配置管理系统(如Spring Cloud Config),为云原生应用提供动态的依赖管理和配置更新能力。
- Serverless架构:无服务器计算模式下,函数即服务(FaaS)平台自动管理资源分配和扩展。尽管在这种环境下不再需要传统的IoC容器,但类似的思想仍然适用于定义和管理函数之间的依赖。
三、特点
IOC(Inversion of Control,控制反转)设计模式 是一种通过将对象的创建和依赖关系管理交给外部容器来实现松耦合的设计模式。它通过依赖注入(DI)等方式解耦系统中的组件,从而提升系统的可扩展性、可维护性和测试性。然而,像任何设计模式一样,IOC模式也有其优缺点。
优点
-
降低耦合度
- IOC通过将依赖关系交给容器管理,避免了类与类之间的紧耦合。类之间不需要知道对方的具体实现,减少了模块之间的依赖,提高了系统的灵活性和可扩展性。
-
提高代码的可维护性
- 由于类不再直接管理其依赖关系,修改某个组件的实现不会直接影响到其他组件。这使得系统更容易维护,尤其是在大型系统中,修改或替换某个依赖时,不需要修改应用程序的其他部分。
-
增强代码的可测试性
- IOC容器通过依赖注入的方式将依赖项外部化,便于进行单元测试。在测试过程中,可以轻松地替换实际的依赖项为mock对象或模拟实现,独立地测试每个模块。
-
提升系统的灵活性和可扩展性
- IOC容器提供了更为灵活的依赖关系配置。通过配置文件或注解方式,开发者可以在不修改代码的情况下替换不同的实现或改变依赖关系,从而增强系统的扩展性。
-
集中式管理对象生命周期
- IOC容器负责对象的创建、管理和销毁,开发人员无需关注对象的生命周期和依赖关系的维护,从而简化了代码结构。
-
符合“面向接口编程”原则
- IOC设计模式鼓励通过接口来定义依赖,而不是依赖于具体的实现类。这不仅提升了系统的灵活性,也使得系统可以更容易地进行替换和扩展。
-
有助于实现设计模式和最佳实践
- IOC设计模式通常与其他设计模式(如工厂模式、策略模式等)配合使用,使得系统的设计更加规范,符合常见的设计最佳实践。
缺点
-
学习曲线陡峭
- IOC和依赖注入(DI)虽然能带来很大的灵活性,但需要开发者对IOC容器、依赖注入以及相关的配置方式有一定的理解和掌握。在一些小型项目或团队中,过度使用IOC可能会带来额外的学习成本和开发复杂度。
-
增加系统的复杂性
- 在使用IOC时,系统的结构变得更加抽象,特别是在没有合理的设计规范时,可能导致过度依赖配置或容器,导致系统的复杂性增加。
- 例如,多个服务的依赖关系可能通过不同的配置文件或注解来管理,如果管理不当,可能导致系统难以理解和调试。
-
性能开销
- 由于IOC容器负责对象的管理和依赖注入,容器在初始化阶段会进行对象的创建和依赖解析,可能会引入额外的性能开销,尤其是在大型应用中,启动时会有一定的延迟。
- 此外,反射机制(如果使用)也会影响性能,虽然这种影响通常是微不足道的,但在一些高性能要求的场景中可能需要谨慎考虑。
-
调试和跟踪困难
- 由于IOC容器负责管理对象的生命周期和依赖关系,调试时可能不易追踪依赖关系和对象的创建过程。尤其是在大型应用中,依赖关系可能变得非常复杂,不容易找到对象之间的依赖路径和问题所在。
- 此外,依赖注入的配置错误(如错过某个依赖)可能导致应用启动失败,排查这些错误有时会变得复杂。
-
过度使用可能导致设计问题
- 虽然IOC可以有效解耦,但在某些场景中,过度使用IOC可能会导致设计不够清晰。比如,如果没有合理的接口和模块划分,依赖注入可能会导致大量的配置和接口,反而增加了系统的复杂度。
- 如果不加以控制,过度的依赖注入和反转控制可能让代码结构变得难以理解和维护。
-
隐式依赖
- 在一些复杂的IOC实现中,依赖注入可能是隐式的,这意味着开发者可能并不直接看到某个类所依赖的所有对象。在这种情况下,阅读和理解代码可能需要花费额外的时间,尤其是当依赖关系非常复杂时。
-
可能增加配置和管理工作
- 使用IOC容器通常需要大量的配置(如XML文件或注解配置)来管理对象的创建和依赖注入。如果容器配置不当,可能导致配置文件变得非常庞大和复杂,影响代码的清晰度和维护性。
四、实现方式
常见的 IOC 实现方式: 依赖注入(Dependency Injection, DI):最常用的 IOC 实现方式,容器通过构造函数、属性或方法来注入对象的依赖。 服务定位(Service Locator):通过集中管理的方式,容器提供一个访问接口,让程序员通过此接口获取到需要的依赖。
IOC(Inversion of Control,控制反转) 是一种设计模式,它的核心思想是将控制对象创建和依赖关系管理的责任从类内部转移到外部容器中。实现IOC的方式有多种,常见的主要有以下几种:
1. 依赖注入(Dependency Injection, DI)
依赖注入是IOC实现的主要方式之一。它通过将类的依赖关系(即对象的引用)交给外部容器来管理,从而减少类之间的耦合。
依赖注入有三种方式:
-
构造器注入(Constructor Injection)
依赖通过构造器传入。在对象创建时,IOC容器会通过构造函数将依赖注入到目标对象中。public class Service {private final Repository repository;// 依赖通过构造器注入public Service(Repository repository) {this.repository = repository;}public void execute() {repository.doSomething();} }
-
Setter注入(Setter Injection)
依赖通过类的setter方法注入。IOC容器会通过反射调用setter方法为类提供所需的依赖。public class Service {private Repository repository;// 通过setter方法注入依赖public void setRepository(Repository repository) {this.repository = repository;}public void execute() {repository.doSomething();} }
-
接口注入(Interface Injection)
依赖通过接口注入。实现特定接口的类会提供一个方法,允许外部容器注入依赖。public interface RepositoryAware {void setRepository(Repository repository); }public class Service implements RepositoryAware {private Repository repository;@Overridepublic void setRepository(Repository repository) {this.repository = repository;}public void execute() {repository.doSomething();} }
2. 依赖查找(Dependency Lookup)
依赖查找是IOC的另一种实现方式,其中对象本身没有直接接收依赖,而是通过查找容器来获取其依赖。依赖查找通常通过容器的API来获取需要的对象。
- 查找容器:应用程序通过容器API获取依赖对象。
public class Service {private ApplicationContext context;public Service(ApplicationContext context) {this.context = context;}public void execute() {// 依赖查找Repository repository = (Repository) context.getBean(Repository.class);repository.doSomething();}}
依赖查找虽然能实现IOC的目的,但它往往较为依赖容器,且不如依赖注入(DI)方式灵活,因为它涉及到容器的显式调用,违反了“松耦合”的原则。
3. Service Locator
Service Locator模式是一种经典的IOC实现方式。通过一个中央的服务定位器(Service Locator),对象可以在运行时获取依赖。Service Locator实际上是依赖查找的一个变体。
在这种方式中,类通过调用一个服务定位器来查找并获取它所需要的依赖对象。
public class Service {public void execute() {Repository repository = ServiceLocator.getRepository();repository.doSomething();}}
缺点:
- Service Locator模式和依赖查找类似,容易使代码过于依赖容器,违反了松耦合的原则。
- 难以进行单元测试,因为它隐藏了类的依赖关系。
4. 使用框架实现IOC
目前,大多数IOC的实现都是通过一些流行的框架来实现的,最典型的框架包括:
-
Spring Framework
Spring是一个非常流行的Java框架,它通过依赖注入和AOP(面向切面编程)实现了强大的IOC容器。Spring可以通过XML配置、注解配置或者Java配置来实现IOC,自动管理对象的创建、生命周期和依赖注入。-
XML配置方式:
<bean id="service" class="com.example.Service"><constructor-arg ref="repository"/> </bean><bean id="repository" class="com.example.Repository"/>
-
注解配置方式:
@Component public class Service {private final Repository repository;@Autowiredpublic Service(Repository repository) {this.repository = repository;} }@Component public class Repository {public void doSomething() {// ...} }
在Spring中,IOC容器会负责对象的实例化、依赖注入以及生命周期管理。
-
-
Guice (Google)
Guice是Google推出的一个轻量级的DI框架,主要用于Java应用。它同样实现了IOC,使用注解和接口实现依赖注入,支持构造器注入、方法注入等多种方式。public class Service {private final Repository repository;@Injectpublic Service(Repository repository) {this.repository = repository;} }
-
Dagger
Dagger是一个静态依赖注入框架,广泛用于Android应用开发中。它通过代码生成的方式来实现依赖注入,性能较高。@Component public interface ServiceComponent {Service getService(); }@Module public class ServiceModule {@Providespublic Repository provideRepository() {return new Repository();} }
5. 反射机制
在一些情况下,IOC容器使用反射机制动态创建对象并注入依赖。反射机制允许在运行时确定类的构造函数、字段和方法,从而实现依赖注入。
- 反射实例化:在没有框架支持的情况下,可以手动使用反射创建对象并注入依赖。
Constructor<?> constructor = Service.class.getConstructor(Repository.class);Service service = (Service) constructor.newInstance(repository);
注意:反射带来的性能开销较大,不推荐过度使用。
总结
IOC的实现方式多种多样,最常见的有依赖注入(DI)、依赖查找和Service Locator等方式。在现代开发中,使用框架(如Spring、Guice等)是最常见的方式,它们通过提供IOC容器来自动管理对象的创建、生命周期和依赖注入。依赖注入通常被认为是最优的IOC实现方式,因为它能够有效地解耦系统,提升系统的可维护性和测试性。
五、应用场景
IOC 主要用于 解耦 组件、提高灵活性 和 可维护性,其典型应用场景包括:
1. 大型企业级应用开发
在大型应用中,各个模块和组件之间的依赖关系通常非常复杂。通过使用 IOC,可以将这些依赖关系交给外部容器(如 Spring 框架)来管理,从而降低系统的耦合度,使得系统更容易扩展和维护。
场景举例:
- 开发企业级管理系统(如 ERP 系统、CRM 系统等)时,可能涉及多个服务、数据访问层和业务逻辑层,通过 IOC 容器可以方便地注入依赖,进行灵活的模块化和配置。
2. 组件化和插件化的架构
在需要实现插件化或可扩展架构的应用中,IOC 可以帮助动态加载和管理不同的插件或模块。通过定义接口和注入不同的实现类,系统能够在运行时根据配置和需要灵活加载不同的组件。
场景举例:
- 在一个支持多种数据库的应用中,不同的数据库驱动实现可以作为插件模块,在启动时通过 IOC 容器注入和切换。
- 在支付系统中,不同的支付方式(如支付宝、微信支付、银联等)可以作为插件模块,在运行时动态注入。
3. 跨平台开发
在跨平台开发中,不同平台的实现可能会有所不同。通过 IOC,可以将平台相关的实现与平台无关的业务逻辑解耦,使得相同的业务逻辑能够在多个平台上共享。
场景举例:
- 在 Android 和 iOS 平台上开发应用时,可以通过 IOC 将平台相关的代码(如网络请求、文件存储等)与平台无关的业务逻辑解耦,使得相同的业务逻辑代码在不同平台之间共享。
4. 单元测试与Mock
在进行单元测试时,使用 IOC 可以更方便地替换和模拟组件依赖,从而实现更高效的测试。通过 IOC 注入假对象(Mock 对象),可以让测试更加集中在某一单一组件的行为上,而不依赖于其实际的依赖。
场景举例:
- 进行单元测试时,可以用 Mock 对象替代数据库访问层、外部服务等,确保测试只关注业务逻辑本身。
5. Web 应用开发
在 Web 应用开发中,尤其是使用 MVC 架构的应用中,IOC 是非常重要的。通过 IOC 容器,Web 应用可以轻松地管理控制器、服务层和数据访问层之间的依赖关系。Spring MVC 就是通过 IOC 实现了控制器、服务和 DAO 的依赖注入,使得 Web 应用更加松耦合、易于维护。
场景举例:
- 在开发一个 Web 应用时,可以通过 IOC 容器注入控制器(Controller)和服务层(Service),将视图(View)与业务逻辑(Service)和数据层(Repository)解耦,从而简化了 Web 应用的开发和扩展。
6. 异步任务和消息队列
在处理异步任务、消息队列和事件驱动架构时,IOC 可以帮助简化事件处理的注册和触发。使用 IOC 容器管理任务和事件的监听器,可以使得事件和任务处理模块之间的依赖关系更加灵活。
场景举例:
- 在分布式系统中,使用消息队列(如 RabbitMQ、Kafka 等)来异步处理任务时,可以通过 IOC 注入消息处理类,使得消息处理逻辑与其他业务逻辑解耦,提高系统的可扩展性。
在本文中,我们深入探讨了IoC(控制反转)设计模式及其在现代软件开发中的应用。通过引入IoC,我们能够有效地降低模块间的耦合度,提高系统的灵活性和可维护性。希望这些知识对你有所帮助,并能在实际开发中灵活应用,打造更加高效和优雅的代码架构。
相关文章:
IoC设计模式详解:控制反转的核心思想
前言:在软件开发中,设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转(Inversion of Control,IoC) 作为一种设计模式,通过让程序的控制流和对象管理反转,从而使得代码…...
C语言延时实现
C语言延时实现 在C语言中,delay 函数通过空循环实现延时,而不是像其他高级语言(如Python)直接使用 sleep 函数。这种实现方式是基于单片机的特性和C语言的底层操作。下面详细解释为什么这种空循环可以实现延时,以及它…...
CDP集群安全指南-静态数据加密
[一]静态数据加密的架构 CDP 支持两种加密组件,这些组件可以组合成独特的解决方案。在选择密钥管理系统(KMS)时,您需要决定哪些组件能够满足企业的密钥管理和加密需求。 CDP 加密组件 以下是 Cloudera 用于静态数据加密的组件描…...
# LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game)
LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game) 在本篇博客中,我们将深入探讨 LeetCode 第2038题——如果相邻两个颜色均相同则删除当前颜色。该问题涉及字符串处理与游戏策略,旨在考察如何在给定规则下判断游戏的…...
极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现
极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现 目录 极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现1. 极限学习机 (ELM) 算法概述1.1 单隐层前馈神经网络1.2 ELM的优势2. ELM的核心技术2.1 模型定义2.2 随机初始化2.3 最小二乘法2.4…...
【insert 插入数据语法合集】.NET开源ORM框架 SqlSugar 系列
系列文章目录 🎀🎀🎀 .NET开源 ORM 框架 SqlSugar 系列 🎀🎀🎀 文章目录 系列文章目录一、前言 🍃二、插入方式 💯2.1 单条插入实体2.2 批量 插入实体2.3 根据字典插入2.4 根据 Dat…...
什么是.net framework,什么是.net core,什么是.net5~8,版本对应关系
我不知道有多少人和我一样,没学习过.netCore,想要学习,但是版本号太多就蒙了,不知道学什么了,这里解释下各个版本的关系 我们一般开始学习微软的时候,都是开始学习的.netframework,常用的就是4…...
【数据库系统概论】数据库安全性和存取控制和视图机制以及审计、数据加密--复习极简总结版
1. 数据库安全性概述 1.1 数据库安全性的重要性 数据库安全性是保护数据库防止非法访问、数据泄露、篡改或破坏的能力。它随着数据共享和网络化应用的普及而变得至关重要。现实案例: 2016年,某国医院遭受黑客攻击,黑客加密数据库并勒索赎金…...
深入理解计算机系统—虚拟内存(3)
9.9 动态内存分配 虽然可以使用低级的 mmap 和 munmap 函数来创建和删除虚拟内存的区域,但是 C程序员还是会觉得当运行时需要额外虚拟内存时,用 动态内存分配器 更方便,也有更好的可移植性。 动态内存分配器维护着一个进程的虚拟内存区域&…...
Vue项目整合与优化
前几篇文章,我们讲述了 Vue 项目构建的整体流程,从无到有的实现了单页和多页应用的功能配置,但在实现的过程中不乏一些可以整合的功能点及可行性的优化方案,就像大楼造完需要进行最后的项目验收改进一样,有待我们进一步…...
MyBatis 与 MyBatis-Plus 的区别
MyBatis 和 MyBatis-Plus 都是用于简化 Java 应用程序与数据库交互的持久层框架,但它们在功能、易用性和性能优化方面存在显著差异。下面将详细介绍两者之间的区别,并通过具体的代码示例进行对比。 概述 MyBatis:作为一款经典的持久层框架&a…...
如何让大模型不再“已读乱回”——RAG技术助力生成更精确的答案
随着大语言模型(LLM) 的迅猛发展,越来越多的领域开始受益于其强大的自然语言处理能力。从写作到编程,LLM已成为我们日常生活和工作的得力助手。然而,这些看似无所不能的大模型,却有一个致命的弱点ÿ…...
Anaconda环境配置(Windows11+python3.9)
文章目录 一、 下载ANACONDA(1)点击**Free Download**。(2)点击“skip registration”,跳过登录。(3)下载对应操作系统的ANACONDA版本。 二、 安装ANACONDA(1)双击运行安…...
Spring Boot 中的虚拟线程
什么是虚拟线程? 虚拟线程(Virtual Threads)是 Java 19 引入的一项新特性,它属于 Project Loom 项目的一部分。与传统的线程(平台线程)不同,虚拟线程并不是由操作系统直接管理,而是…...
el-table 实现纵向多级表头
为了实现上图效果,最开始打算用el-row、el-col去实现,但发现把表头和数据分成两大列时,数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样,为保持高度样式一致,就需要我们手动去获取最高格的高度之后再设置…...
探秘Kafka源码:关键内容解析
文章目录 一、以kafka-3.0.0为例1.1安装 gradle 二、生产者源码2.1源码主流程图2.2 初始化2.3生产者sender线程初始化2.4 程序入口2.5生产者 main 线程初始化2.6 跳转到 KafkaProducer构造方法 一、以kafka-3.0.0为例 打开 IDEA,点击 File->Open…->源码包解…...
Promise编码小挑战
题目 我们将实现一个 createImage 函数,该函数返回一个 Promise,用于处理图片加载的异步操作。此外,还会实现暂停执行的 wait 函数。 Part 1: createImage 函数 该函数会: 创建一个新的图片元素。将图片的 src 设置为提供的路径…...
PyQt实战——将pcm文本数据转换成.pcm的二进制文件
系类往期文章: PyQt5实战——多脚本集合包,前言与环境配置(一) PyQt5实战——多脚本集合包,UI以及工程布局(二) PyQt5实战——多脚本集合包,程序入口QMainWindow(三&…...
数据结构之线性表
1.什么是线性表 线性表的概念 定义:线性表是由n个数据元素组成的有限序列。每个数据元素(除了第一个和最后一个)都有且仅有一个前驱和一个后继。逻辑结构:线性表的逻辑结构可以用一个序列来表示,例如 L(a1,a2,…,an)。…...
量子行走的干涉性和叠加性
需要注意公式的一些特殊情况,举例,当dj2和dj3 dj2 dj3...
Fabric环境部署-安装Go
安装go语言环境 国内镜像:Go下载 - Go语言中文网 - Golang中文社区 1.选择版本下载后解压:注意go1.11.linux-amd64.tar.gz换成你下的 sudo tar zxvf go1.21.linux-amd64.tar.gz -C /usr/local 2.. 创建Go目录 mkdir $HOME/go 3. 用vi打开~./bashrc&…...
网站设计总结后期维护与更新的重要性
当我们谈论网站设计时,往往会聚焦在初始阶段的创意和实现上。然而,一旦网站建成并上线,后期维护与更新的重要性就显得尤为突出。一个网站的成功不仅取决于其初始设计,更在于持续的维护与更新。 首先,后期维护能够确保网…...
『SQLite』详解运算符
内容摘要:本节讲解运算符,包括:算术运算符、比较运算符、逻辑运算符和位运算符。 什么是运算符? 运算符是一个保留字或字符,主要用于 SQLite 语句的 WHERE 子句中执行操作。它用于指定 SQLite 语句中的条件࿰…...
计算机网络--根据IP地址和路由表计算下一跳
一、必备知识 1.无分类地址IPV4地址网络前缀主机号 2.每个IPV4地址由32位二进制数组成 3. /15这个地址表示网络前缀有15位,那么主机号32-1517位。 4.地址掩码(子网掩码):所对应的网络前缀为1,主机号为0。 5.计算下…...
如何使用 Ansys OptiSlang 同时运行多个参数化设计研究
了解如何通过使用 OptiSLang 同时运行多个参数化设计研究来提高工作效率。 了解参数化设计研究的重要性 参数化设计研究在工程和设计过程中起着至关重要的作用。通过改变输入参数,工程师可以探索不同设计选择的效果,并优化其设计以满足性能、成本或其他…...
《 拼数 》
题目描述 设有 nn 个正整数 a1…ana1…an,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。 输入格式 第一行有一个整数,表示数字个数 nn。 第二行有 nn 个整数,表示给出的 nn 个整数 aiai。 输出格…...
Memcached CAS 命令
Memcached CAS(Check-And-Set 或 Compare-And-Swap) 命令用于执行一个"检查并设置"的操作 它仅在当前客户端最后一次取值后,该key 对应的值没有被其他客户端修改的情况下, 才能够将值写入。 检查是通过cas_token参数进…...
ElasticSearch基础-文章目录
ElasticSearch学习总结1(环境安装) ElasticSearch学习总结2(基础查询) ElasticSearch学习总结3(.NetCore操作ES) ElasticSearch学习总结4(sql操作ES) ElasticSearch学习总结5&am…...
后台管理系统动态面包屑Breadcrumb组件的实现
在后管理系统开发中,面包屑导航是一个非常常见的功能,通常是根据当前的 url 自动生成面包屑导航菜单,当跳转路由发生变化时,面包屑导航都会随之发生变化,即动态面包屑。 要完成动态面包屑我们需要制作一个动态数组&am…...
java项目之校园管理系统的设计与实现(源码+文档)
风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园管理系统的设计与实现。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: springboot校园…...
浅谈棋牌游戏开发流程八:运维与数据分析
一、前言:为什么“云端运维”和“数据分析”如此重要? 在前面几篇文章中,我们已经从客户端、后端架构、用户系统、房间匹配与对局流程、数据库设计与优化、支付与充值、安全与反外挂等角度,系统性地搭建了一个棋牌游戏的基本框架…...
uniapp:微信小程序文本长按无法出现复制菜单
一、问题描述 在集成腾讯TUI后,为了能让聊天文本可以复制,对消息组件的样式进行修改,主要是移除下面的user-select属性限制: user-select: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms…...
跨物种筛选同源基因
工具:R:biomaRt 原始文件:human、mouse、macaque、marmoset四个物种的gene list,有些是用ensembl ID,有的是用gene name来表示。 目的:找到四个物种的gene list之间的1v1同源基因 1. 找到物种间的1v1同源…...
大模型数据采集和预处理:把所有数据格式,word、excel、ppt、jpg、pdf、表格等转为数据
大模型数据采集和预处理:把所有数据格式,word、excel、ppt、jpg、pdf、表格等转为数据 文本/图片/表格,分别提取处理工具选择不同格式文件,使用不同工具处理1. 确认目标2. 分析过程(目标-手段分析法)3. 实现步骤4. 代码封装效果展…...
k8s修改存储目录-介绍
k8s修改存储目录-介绍 文章目录 k8s修改存储目录-介绍总结:介绍指定 Docker 或 containerd 镜像和容器存储目录Docker 存储目录containerd 存储目录 指定 Kubelet 的存储目录指定 Pod 和容器存储目录 docker 运行时,迁移目录实操:https://blo…...
【电源专题】为什么测试电源的SW波形上冲振荡之前的0V电位要先来个小的下降
在同步电源的开关节点SW波形测试中,你可能会发现周期性的SW波形在上升前的一小段时间时间内会有一个小小的下跌,这个下跌会低于0V。那么这个下跌是怎么来的呢? 如下所示为某降压转换器的SW开关节点波形: 其展开后可以看到在上升之前有20ns左右的时间,SW电压是下跌…...
常见的反规范化技术
在数据库设计中,数据规范化和反规范化是两种重要的策略,它们在一定程度上存在权衡。规范化通过组织表结构,减少数据冗余,提高数据一致性和降低更新异常,使数据存储更加高效、可靠。然而,过度的规范化会导致…...
Linux中隐藏操作身法
从历史记录中删除指定的命令 假设历史记录中已经包含了一些你不希望记录的命令。这种情况下我们怎么办?很简单。通过下面的命令来删除: history | grep "keyword"例如:history | grep set o history 批量第二条和第四条删除: sed…...
Transformer知识梳理
Transformer知识梳理 文章目录 Transformer知识梳理什么是Transformer?语言模型迁移学习 Transformer结构注意力层原始结构 总结 什么是Transformer? 语言模型 Transformer模型本质上都是预训练语言模型,大部分采用自监督学习(S…...
Nexus Message Transaction Services(MTS)
Nexus 系列交换机遇到以下情形时,可以尝试查看是否是 MTS 消息卡在缓冲区过多,因为 MTS 负责处理模块内以及跨模块(包括跨管理引擎)的各服务之间的消息路由和排队。 • CPU 高 • 命令行无响应、响应慢 • 控制平面中断 • 流量问…...
网络编程基础:连接Java的秘密网络
1 网络编程的重要性 网络编程允许Java应用程序与其他计算机或设备进行通信。这包括从简单的数据传输到复杂的分布式系统和Web服务。 2 Java网络编程的核心类 Java提供了多个类来支持网络编程: InetAddress:表示网络上的IP地址。 URL:表示统…...
uniapp中判断设备类型
全局变量: 在 UniApp 中,你可以通过 uni.getDeviceInfo 获取设备信息,并将设备类型全局存放。通常,这些信息可以存放在 app.vue 的全局变量中,以便在整个应用中访问。 以下是如何在 app.vue 中实现这一功能的完整代码…...
数据可视化分析详解
数据可视化分析是一种通过图形、表格、图标和其他视觉元素来呈现数据的方式,使得数据更易于理解和分析。以下是关于数据可视化分析的一些关键点: 一、定义与目的 数据可视化分析是指利用图形化手段,清晰地有效地传达与沟通信息。它将数据以…...
_使用CLion的Vcpkg安装SDL2,添加至CMakelists时报错,编译报错
语言:C20 编译器:gcc 14.2 摘要:初次使用Vcpkg添加SDL2,出现CMakelists找不到错误、编译缺失main错误、运行失败错误。 CMakelists缺失错误: 使用CLion的Vcpkg安装SDL2时,按照指示把对应代码添加至CMakel…...
QT中Qstring和QByteArray有什么区别?
数据存储内容方面 QString: 主要用于存储和处理Unicode编码的文本字符串。它能够很好地处理包含各种语言字符的文本信息,如中文、日文、韩文等多种语言文字。例如,QString str "你好,世界!";可以方便地存储…...
Viggle AI:支持小孩或者卡通人物吗? [Viggle AI实战教程] – 第2篇
历史文章 Suno AI API接入 - 将AI音乐接入到自己的产品中,支持120并发任务 万物皆能舞,AI让你秒变“舞”林高手 – Viggle AI“舞”所不能 Viggle AI:打造爆款 AI 视频,让照片 “踢” 起足球 Viggle AI:开启3D动画…...
庐山派K230学习日记4 PWM控制
1 本节介绍 📝本节您将学习如何通过将K230开发板的GPIO引脚复用为PWM功能并输出PWM信号;实现输出PWM信号及控制板载无源蜂鸣器发出声音。 🏆学习目标 1️⃣如何将GPIO引脚配置为PWM模式,通过40Pin排针中的部分引脚来输出PWM信号…...
Android配件应用默认启动与USB权限申请区别
使用效果: USB配件授权演示 选择USB配件默认打开应用 申请USB配件使用权限...
【车载开发系列】GPIO模式分类
【车载开发系列】GPIO模式分类 这里写目录标题 【车载开发系列】GPIO模式分类一. GPIO概念二. GPIO的模式区分三. GPIO的八大模式1)推挽输出(Output push-pull)2)开漏输出(Output open-drain)3)…...
uniapp--HBuilder开发
提示:本文为学习内容,若有错误,请联系作者,谦虚受教。 文章目录 前言一、下载HBuilder二、添加modbus相关库1.下载nodejs2.下载modbus库3.项目添加modbus库 三、HBuilder相关功能语句1.文件夹说明2.消息信息框3.开关按钮4.选中按钮…...