当前位置: 首页 > news >正文

IoC设计模式详解:控制反转的核心思想

前言:在软件开发中,设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转(Inversion of Control,IoC) 作为一种设计模式,通过让程序的控制流和对象管理反转,从而使得代码的解耦性和可维护性大大提高。
学习Spring,其中一个核心——Spring IoC容器,则是这一模式在Spring框架中的具体实现。

一、IoC简介

IoC(控制反转)是一种设计模式(原则),核心思想是将对象的创建、初始化和依赖关系的管理从程序中反转出来,交由外部容器(例如 Spring)来负责。

也就是说,程序不再控制对象的创建和生命周期,而是通过外部容器来进行管理,这样可以实现更高的解耦和灵活性。

1d8ce4dd-a4ea-4e26-93ea-c3d26dda88c6

控制反转显然是一个抽象的概念,举一个鲜明的例子来说明:

在现实生活中,人们要用到一样东西的时候,第一反应就是去找到这件东西,比如想喝新鲜橙汁,在没有饮品店的日子里,最直观的做法就是:买果汁机、买橙子,然后准备开水。值得注意的是:这些都是你自己 “主动”创造的过程,也就是说一杯橙汁需要你自己创造。

然而到了今时今日,由于饮品店的盛行,当我们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,通过电话等渠道描述你的需要、地址、联系方式等,下订单等待,过一会儿就会有人送来橙汁了。

image

请注意你并没有“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也完全达到了你的要求,甚至比你创造的要好上那么一些。

所以控制反转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模式的流行。

    image

​ ”软件开发教父“—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模式也有其优缺点。

优点
  1. 降低耦合度

    • IOC通过将依赖关系交给容器管理,避免了类与类之间的紧耦合。类之间不需要知道对方的具体实现,减少了模块之间的依赖,提高了系统的灵活性和可扩展性。
  2. 提高代码的可维护性

    • 由于类不再直接管理其依赖关系,修改某个组件的实现不会直接影响到其他组件。这使得系统更容易维护,尤其是在大型系统中,修改或替换某个依赖时,不需要修改应用程序的其他部分。
  3. 增强代码的可测试性

    • IOC容器通过依赖注入的方式将依赖项外部化,便于进行单元测试。在测试过程中,可以轻松地替换实际的依赖项为mock对象或模拟实现,独立地测试每个模块。
  4. 提升系统的灵活性和可扩展性

    • IOC容器提供了更为灵活的依赖关系配置。通过配置文件或注解方式,开发者可以在不修改代码的情况下替换不同的实现或改变依赖关系,从而增强系统的扩展性。
  5. 集中式管理对象生命周期

    • IOC容器负责对象的创建、管理和销毁,开发人员无需关注对象的生命周期和依赖关系的维护,从而简化了代码结构。
  6. 符合“面向接口编程”原则

    • IOC设计模式鼓励通过接口来定义依赖,而不是依赖于具体的实现类。这不仅提升了系统的灵活性,也使得系统可以更容易地进行替换和扩展。
  7. 有助于实现设计模式和最佳实践

    • IOC设计模式通常与其他设计模式(如工厂模式、策略模式等)配合使用,使得系统的设计更加规范,符合常见的设计最佳实践。

缺点
  1. 学习曲线陡峭

    • IOC和依赖注入(DI)虽然能带来很大的灵活性,但需要开发者对IOC容器、依赖注入以及相关的配置方式有一定的理解和掌握。在一些小型项目或团队中,过度使用IOC可能会带来额外的学习成本和开发复杂度。
  2. 增加系统的复杂性

    • 在使用IOC时,系统的结构变得更加抽象,特别是在没有合理的设计规范时,可能导致过度依赖配置或容器,导致系统的复杂性增加。
    • 例如,多个服务的依赖关系可能通过不同的配置文件或注解来管理,如果管理不当,可能导致系统难以理解和调试。
  3. 性能开销

    • 由于IOC容器负责对象的管理和依赖注入,容器在初始化阶段会进行对象的创建和依赖解析,可能会引入额外的性能开销,尤其是在大型应用中,启动时会有一定的延迟。
    • 此外,反射机制(如果使用)也会影响性能,虽然这种影响通常是微不足道的,但在一些高性能要求的场景中可能需要谨慎考虑。
  4. 调试和跟踪困难

    • 由于IOC容器负责管理对象的生命周期和依赖关系,调试时可能不易追踪依赖关系和对象的创建过程。尤其是在大型应用中,依赖关系可能变得非常复杂,不容易找到对象之间的依赖路径和问题所在。
    • 此外,依赖注入的配置错误(如错过某个依赖)可能导致应用启动失败,排查这些错误有时会变得复杂。
  5. 过度使用可能导致设计问题

    • 虽然IOC可以有效解耦,但在某些场景中,过度使用IOC可能会导致设计不够清晰。比如,如果没有合理的接口和模块划分,依赖注入可能会导致大量的配置和接口,反而增加了系统的复杂度。
    • 如果不加以控制,过度的依赖注入和反转控制可能让代码结构变得难以理解和维护。
  6. 隐式依赖

    • 在一些复杂的IOC实现中,依赖注入可能是隐式的,这意味着开发者可能并不直接看到某个类所依赖的所有对象。在这种情况下,阅读和理解代码可能需要花费额外的时间,尤其是当依赖关系非常复杂时。
  7. 可能增加配置和管理工作

    • 使用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,我们能够有效地降低模块间的耦合度,提高系统的灵活性和可维护性。希望这些知识对你有所帮助,并能在实际开发中灵活应用,打造更加高效和优雅的代码架构。

3ec794dacde34583aafafe15b1490012

相关文章:

IoC设计模式详解:控制反转的核心思想

前言&#xff1a;在软件开发中&#xff0c;设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09; 作为一种设计模式&#xff0c;通过让程序的控制流和对象管理反转&#xff0c;从而使得代码…...

《云原生安全攻防》-- K8s安全配置:CIS安全基准与kube-bench工具

在本节课程中&#xff0c;我们来了解一下K8s集群的安全配置&#xff0c;通过对CIS安全基准和kube-bench工具的介绍&#xff0c;可以快速发现K8s集群中不符合最佳实践的配置项&#xff0c;及时进行修复&#xff0c;从而来提高集群的安全性。 在这个课程中&#xff0c;我们将学习…...

LINUX下载编译gtk

下载 选择自己合适的版本 GNOME / gtk GitLab 下载meson GNOME / gtk GitLab 编译 BUILD_DIRbuilddir INSTALL_DIR${HOME}/gtk-resultMESON_PATHpwd/meson-1.6.1/meson.py${MESON_PATH} setup \--prefix ${INSTALL_DIR} \${BUILD_DIR}cd builddir${MESON_PATH} compile…...

基于VSCode软件框架的RISC-V IDE MRS2正式上线发布

基于VSCode软件框架的RISC-V IDE MRS2正式上线发布 一、概述 MounRiver Studio Ⅱ(MRS2)为MounRiver Studio的换代版本&#xff0c;从V2.1开始&#xff0c;框架更换至更现代的VSCode&#xff0c;并深度定制开发。在工程管理、代码编辑、编译、调试等方面均兼容之前版本&#…...

AWS re:Invent 2024 - Dr. Werner Vogels 主题演讲

今年&#xff0c;我有幸亲临现场参加了所有的 keynote&#xff0c;每一场都让我感受到深深的震撼。无论是全新的功能发布&#xff0c;还是令人眼前一亮的新特性展示&#xff0c;每一场 keynote 都精彩纷呈&#xff0c;充满干货&#xff0c;值得反复学习和回味。 恰好&#xff…...

前端小案例——520表白信封

前言&#xff1a;我们在学习完了HTML和CSS之后&#xff0c;就会想着使用这两个东西去做一些小案例&#xff0c;不过又没有什么好的案例让我们去练手&#xff0c;本篇文章就提供里一个案例——520表白信封 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主…...

FPGA随记——过约束

什么是过约束&#xff1f; 从字面意思来看&#xff0c;所谓过约束是指约束过紧了。这个“过”体现在setup requirement变小了&#xff0c;对于单周期路径&#xff0c;这个值通常与时钟周期一致&#xff0c;但在过约束情况下&#xff0c;等效于这个值变小了&#xff0c;也就是时…...

如何利用云计算进行灾难恢复?

云计算环境下的灾难恢复实践指南 天有不测风云&#xff0c;企业的IT系统也一样&#xff0c;我见过太多因为没有做好灾备而吃大亏的案例。今天就和大家聊聊如何用云计算来做灾难恢复。 一个惊心动魄的真实案例&#xff1a;某电商平台的主数据中心因为市政施工不小心挖断了光纤…...

【华为OD-E卷 - 九宫格按键输入 100分(python、java、c++、js、c)】

【华为OD-E卷 - 九宫格按键输入 100分&#xff08;python、java、c、js、c&#xff09;】 题目 九宫格按键输入&#xff0c;有英文和数字两个模式&#xff0c;默认是数字模式&#xff0c;数字模式直接输出数字&#xff0c;英文模式连续按同一个按键会依次出现这个按键上的字母…...

基于AI大模型的医院SOP优化:架构、实践与展望

一、引言 1.1 研究背景与意义 近年来,人工智能(AI)技术取得了迅猛发展,尤其是大模型的出现,为各个领域带来了革命性的变化。在医疗领域,AI 医疗大模型正逐渐崭露头角,展现出巨大的应用潜力。随着医疗数据的海量积累以及计算能力的大幅提升,AI 医疗大模型能够对复杂的…...

Linux快速入门-一道简单shell编程题目

编写一个 Shell 程序。 功能&#xff1a;在用户家目录下创建一个文件夹myshell&#xff1b;进入此文件夹&#xff1b;在文件中创建文件aa.sh&#xff0c;如果文件夹或文件存在&#xff0c;则提示对象已存在&#xff0c;不创建。 代码编写 #!/bin/bash#获取用户家目录:方便后…...

Hive如何创建自定义函数(UDF)?

目录 1 自定义UDF函数基础 2 自定义UDF函数案例 3 创建临时函数 4 创建永久函数 1 自定义UDF函数基础 1. 内置函数:Hive 自带了一些函数...

聊聊前端框架中的process.env,env的来源及优先级(next.js、vue-cli、vite)

在平时开发中&#xff0c;常常使用vue、react相关脚手架创建项目&#xff0c;在项目根目录可以创建.env、.env.[mode]&#xff08;mode为development、production、test)、.env.local等文件&#xff0c;然后在项目中就可以通过process.env来访问相关的环境变量了。 下面针对如下…...

linux shell脚本 【分支结构case...in 、循环结构、函数】内附练习

1.思维导图 2.练习 1.定义一个find函数&#xff0c;查找ubuntu和root的gid 2.定义一个数组&#xff0c;写一个函数完成对数组的冒泡排序 bubble() {n${#arr[*]}for((i0;i<n-1;i));dofor((j0;j<n-1-i;j));doif ((arr[j]>arr[j1]));thentemp${arr[j]}arr[j]${arr[j1]}a…...

VSCode 终端显示“pnpm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本”

VSCode 终端显示“pnpm : 无法加载文件 C:\Program Files\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本”VSCode 终端显示“pnpm : 无法加载文件 C:\Program Files\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本”解决方案&#xff1a; 1.用get-ExecutionP…...

Android ActionBar 技术深度解析

Android ActionBar 技术深度解析 概述 ActionBar 是 Android 应用中的一个核心 UI 组件,用于提供导航、操作和品牌展示。它通常位于应用窗口的顶部,包含应用的标题、导航按钮、操作项等。ActionBar 自 Android 3.0(API 11)引入,并在 Android 5.0(API 21)后被 Toolbar …...

matlab-数字滤波器设计与实战

文章目录 数字滤波器设计FIR 滤波器设计IIR 滤波器设计巴特沃斯滤波器切比雪夫 I 型滤波器切比雪夫II型椭圆滤波器线性相位与非线性相位零相位响应数字滤波器实战数字滤波器产生延迟的主要原因补偿滤波引入的延迟补偿常量滤波器延迟补偿与频率有关的延迟从信号中除去不需要的频…...

JDK的运作原理

JDK&#xff08;Java Development Kit&#xff09;是Java开发者用来构建、编译、调试和运行Java应用程序的一套工具包。其核心原理涉及到Java语言的编译、执行以及Java虚拟机&#xff08;JVM&#xff09;的运作等多个方面。 1. Java编译原理 Java是一种先编译后解释执行的语言。…...

el-table 实现纵向多级表头

为了实现上图效果&#xff0c;最开始打算用el-row、el-col去实现&#xff0c;但发现把表头和数据分成两大列时&#xff0c;数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样&#xff0c;为保持高度样式一致&#xff0c;就需要我们手动去获取最高格的高度之后再设置…...

Android Studio 下载安装教程(2024 更新版),附详细图文

今天&#xff0c;为大家带来的是Android Studio 2024更新版的下载安装教程&#xff0c;包含详细图文步骤。 随着 Android Studio 的不断更新&#xff0c;自从引入 Koala 系列后&#xff0c;其版本号的命名规则也发生了变化。以本次更新为例&#xff0c;版本号为 2024.2.1&#…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...