SpringBoot解耦:控制反转(IOC)与依赖注入(DI)

逆向分析第一步:如何从HEX文件‘还原’出单片机的原始程序与数据? 本文详细解析了如何从HEX文件逆向分析出单片机的原始程序与数据,涵盖了固件逆向的底层逻辑与实践。通过介绍HEX文件的结构、内存映像重建技术以及专业工具链的使用,帮助读者掌握从十六进制数据到可执行代码的完整流程,适用于嵌入式系统开发和逆向工程领域。 阅读详情

一、引言

        在构建Spring Boot Web应用时,我们通常采用控制层、业务逻辑层、数据访问三层架构,其核心目标之一是实现模块间的解耦,让每一层职责单一、独立演化。

        然而,传统的“谁使用,谁创建”的对象管理方式(如在Controller中new Service)却与这一目标背道而驰,造成了层与层之间的硬编码耦合。这种耦合使得代码僵化、难以测试和维护——修改一个组件,往往需要牵连修改所有依赖它的组件。

        Spring Boot框架为解决这一核心问题提供了优雅的答案:控制反转与依赖注入

二、控制反转与依赖注入如何实现低耦合

2.1控制反转与依赖注入到底是什么呢?

        首先,通过概念来初步理解这两个名词。

控制反转:Inversion 0f Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

        另外大家还需要知道Bean对象

Bean对象:IOC容器中创建、管理的对象,称之为Bean。

2.2传统代码的缺点:强耦合的订单案例

        现在,我通过一个订单案例的代码来让大家理解这个两个概念。

        在典型的Spring Boot Web应用中,我们普遍采用控制器层(Controller)、服务层(Service)、数据访问层(Dao/Mapper) 的三层架构。这种分层的目的就是为了解耦,让每一层各司其职。

但理想很丰满,现实却很骨感。在没有引入Springboot框架的帮助下我们可能会写出这样的代码:

controller层:

// 传统方式:强耦合的代码
@RestController // 即使有注解,但没有IoC容器,也无法自动注入
public class OrderController {

    // 问题所在:Controller 直接「new」了一个具体的 Service 实现类
    private OrderService orderService = new OrderServiceImpl();

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Long id) {
        return orderService.getOrderById(id);
    }
}

Service层:

// 订单服务接口
public interface OrderService {
    Order getOrderById(Long id);
}

// 订单服务实现类
public class OrderServiceImpl implements OrderService {

    // 问题同样存在:Service 直接「new」了一个具体的 Dao 实现类
    private OrderDao orderDao = new OrderDaoImpl();

    @Override
    public Order getOrderById(Long id) {
        return orderDao.findById(id);
    }
}

这段代码的“痛点”非常明显:

  • 高度耦合:OrderController 牢牢地绑定了 OrderServiceImpl 这个具体实现。如果有一天我们需要一个 NewOrderServiceImpl(比如使用了新的业务逻辑),我们就必须修改 OrderController 的源代码,将 new OrderServiceImpl() 改为 new NewOrderServiceImpl()。

  • 难以测试:如果我们想对 OrderController 进行单元测试,几乎不可能让它使用一个模拟的(Mock)OrderService。因为它的依赖是内部固化的,我们无法从外部替换。

  • 违背开闭原则:对扩展开放,对修改关闭。这里,任何依赖的变更都导致了源代码的修改。

这种“谁使用,谁创建”的模式,导致了各层之间像锁链一样环环相扣,任何一个环节的变动都可能导致了源代码的修改。

2.3 控制反转与依赖注入的解决方案

        那么我们引入控制反转与依赖注入的策略,不要在你的组件内部创建依赖,而是让外部容器(IOC容器)创建好,然后“注入”给你。

让我们看看改造后的代码:

        controller层:在Controller中,我们也不再创建Service,而是声明:“我需要一个OrderService”。

@RestController
public class OrderController {

    @Autowired // 关键注解:请求容器将所需的OrderService注入到此
    private OrderService orderService; // 面向接口编程,而非具体实现!

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Long id) {
        return orderService.getOrderById(id);
    }
}

        service层:我们使用注解(如 @Component, @Service, @Repository)标记类,告诉Spring:“请创建并管理我这个类的实例(Bean)。”

@Service // 关键注解:声明这个类是一个Service,由Spring容器管理(成为一个Bean)
public class OrderServiceImpl implements OrderService {

    @Autowired // 关键注解:请求容器将所需的OrderDao注入到此
    private OrderDao orderDao; // 不再自己new!

    @Override
    public Order getOrderById(Long id) {
        return orderDao.findById(id);
    }
}

@Repository
public class OrderDaoImpl implements OrderDao {
    // ... 数据访问逻辑
}

2.4 控制反转与依赖注入的实现分析

结合上面修改前和修改后的代码,大家应该能发现:

  • 实现控制反转(IoC)的操作就是:OrderController 和 OrderServiceImpl 的创建控制权,从程序员手中(new关键字)“反转”到了Spring IOC容器手中。
  • 实现依赖注入(DI)的操作就是:Spring容器负责创建好 OrderServiceImpl 和 OrderDaoImpl 的实例(Bean)。当创建 OrderController 时,容器发现它需要一个 OrderService,于是自动找到 OrderServiceImpl 这个Bean,并“注入”到 OrderController 的对应字段中。OrderServiceImpl 对 OrderDao 的依赖也是如此注入的。

那么带来的好处也显而易见了:

  • 彻底解耦:OrderController 只依赖于 OrderService 这个接口,完全不知道也不关心其具体实现是谁。这意味着,我们可以随时在配置中将注入的实现从 OrderServiceImpl 切换到 NewOrderServiceImpl,而 OrderController 的代码一行都不用改!

  • 易于测试:在测试时,我们可以利用Spring的测试框架或Mock工具,轻松地为 OrderController 注入一个模拟的 OrderService,从而进行纯净的单元测试。

2.5 通过生活场景理解控制反转与依赖注入

        通过上述代码示例,大家一定对控制反转与依赖注入有了初步的感受了。接下来,我将通过生活场景进一步说明,帮助大家理解其运作机制。

        首先,我们先梳理一下这个过程中的各个角色:需要依赖注入的类(如controller类),对象的创建控制权交给IOC容器的类(如service类),IOC容器,bean对象。

        现在大家想象一个生活场景。工厂需要招牌不同技能的工人,工人需要应聘一家工厂。于是工人将自己的资料交给中介公司,工厂向中介公司提出用工需求。

我们梳理一下这个场景中对应的关系:

1. 工人(技能提供者)

  • 对应:需要将控制权交给IOC容器的类(如Service、Repository等)

  • 行为:到中介公司(IoC容器)登记注册,成为Bean对象

  • 特点:被动等待分配工作,不关心为谁服务

2. 工厂(服务使用者)

  • 对应:需要依赖注入的类(如Controller、其他Service等)

  • 行为:向中介公司提出用工需求(声明依赖)

  • 特点:主动提出需求,但不亲自招聘

3. 中介公司(协调管理者)

  • 对应:IOC容器(ApplicationContext)

  • 行为:接收工人登记,响应工厂需求,组织协作

  • 特点:掌握全局,负责调度

4. 工人资料/工人本身

  • 对应:Bean对象

  • 身份:在IOC容器中注册的具体实例

  • 状态:随时准备被"派遣"到需要的地方

那么完整的工作的流程就是这样:

工人登记 → 中介管理 → 工厂申请 → 中介派遣 → 协作生产

1. 【工人登记】OrderService类加上@Service注解 → 成为Bean
   (电工到中介公司登记:"我会电工技能")

2. 【中介管理】IoC容器创建并管理OrderService实例
   (中介公司记录电工的联系方式和技能等级)

3. 【工厂申请】OrderController声明@Autowired OrderService
   (建筑队向中介申请:"我需要一个电工")

4. 【中介派遣】IoC容器将OrderService Bean注入OrderController  
   (中介派电工到建筑队工作)

5. 【协作生产】OrderController使用OrderService完成业务
   (建筑队和电工协作盖房子)

需要注意的是:

  • 工人和工厂都是Bean:在Spring中,Controller、Service、Repository等被管理的类都是Bean

  • 角色是相对的:一个Service可能同时是"工人"(被Controller使用)和"工厂"(使用Repository)

  • 中介是核心:IoC容器作为中央协调者,解耦了工人和工厂的直接依赖关系

        概念和运作机制都理解清楚后,我们接下来就详细了解控制反转和依赖注入在开发中具体的代码实现和注意点。

三、IOC详解

3.1 声明Bean的注解

        要把某个对象交个IOC容器管理,需要在对应的类上面加上如下注解之一:

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller@Component的衍生注解标注在控制层类上
@Service@Component的衍生注解标注在业务层类上
@Repository@Component的衍生注解标注在数据访问层类上(由于与mybatis整合,用的少,MyBatis通常使用@Mapper接口替代)

        我们可以查看@Controller@Service@Repository的源码,三个注解都继承所有@Component功能。

// @Service 的源码定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component  // 关键!@Service 本身被 @Component 注解标记
public @interface Service {
    String value() default "";
}

// @Controller 的源码定义  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component  // 关键!@Controller 本身被 @Component 注解标记
public @interface Controller {
    String value() default "";
}

// @Repository 的源码定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component  // 关键!@Repository 本身被 @Component 注解标记
public @interface Repository {
    String value() default "";
}

3.2 为什么需要衍生注解而不仅仅是@Component?

   虽然@Controller、@Service、@Repository在功能上与@Component完全等价,但它们的存在有着重要的设计意义。

// 不好的做法:语义不清晰
@Component
public class OrderController { ... }

@Component  
public class OrderServiceImpl { ... }

@Component
public class OrderDaoImpl { ... }

// 好的做法:语义明确,一目了然
@Controller
public class OrderController { ... }    // 明确表示这是控制器层(实际开发过程中我们会用到@RestController)

@Service  
public class OrderServiceImpl { ... }   // 明确表示这是业务逻辑层

@Repository
public class OrderDaoImpl { ... }       // 明确表示这是数据访问层

好比职场中的职位标签:

  • 所有人都可以统称为"员工"(@Component)

  • 但具体分为"项目经理"(@Controller)、"技术专家"(@Service)、"财务专员"(@Repository)

  • 职位标签让职责分工更加清晰

        另外还有一些其他的原因,例如使用特定注解可以让代码自动体现三层架构,还能享受特定的框架特性,便于AOP切面编程。不过最重要的原因还是上述介绍的语义化表达,让架构层次清晰。

3.3 bean的命名

我们在声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。

        大家可以通过下面这个代码进行直观理解bean命名的两种方式。

@Service  // 没有指定bean名称,使用默认规则
public class OrderServiceImpl implements OrderService {
    // 这个bean在Spring容器中的名字将是:"orderServiceImpl"
    // (类名首字母小写)
}

@Service("myOrderService")  // 通过value属性指定bean名称
public class OrderServiceImpl implements OrderService {
    // 这个bean在Spring容器中的名字将是:"myOrderService"
    // (自定义名称)
}

3.4 Bean声明生效的关键

        前面我们知道了四大注解(@Component, @Controller, @Service, @Repository),但有一个关键问题:仅仅在类上添加这些注解,Spring并不能自动发现并创建Bean,我们还需要配置@ComponentScan。

        Spring容器启动时,会查看是否配置了@ComponentScan。如果有,就会按照指定路径去"扫描"所有类文件。然后发现带有@Component及其衍生注解的类,就创建对应的Bean实例将这些Bean纳入IoC容器管理。

        该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 。当我们创建一个springboot项目的时候,我们就可以看到启动类是这样的。

@SpringBootApplication  // 这是一个复合注解!
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

        没错就是@SpringBootApplication。在idea中点开这个注释,我们可以看到它的组成

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan  // 看!它已经内置在这里了!
public @interface SpringBootApplication {
}

        所以为什么是声明在启动类上呢?那是因为@SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。

        通过下面这个项目结构的图例大家能够清晰的理解

com.example
└── myapp
    ├── Application.java          // 启动类
    ├── controller
    │   ├── UserController.java   // 会被扫描到
    │   └── OrderController.java  // 会被扫描到
    ├── service
    │   ├── UserService.java      // 会被扫描到
    │   └── OrderService.java     // 会被扫描到
    └── config
        └── WebConfig.java        // 会被扫描到

        如果类不在扫描范围内:

com.example
├── myapp
│   ├── Application.java          // 启动类
│   └── controller
│       └── UserController.java   // 会被扫描到
└── external
    └── ExternalService.java      // 不会被扫描到!(不在子包中)

        那如果大家需要扫描其他包,也可以这样配置:

@SpringBootApplication
@ComponentScan(basePackageClasses = {
    Application.class,        // 扫描启动类所在包
    ExternalService.class     // 扫描ExternalService所在包
})
public class Application {
    // ...
}


//不推荐,不够安全
@SpringBootApplication
@ComponentScan(basePackages = {
    "com.example.myapp",      // 默认路径
    "com.example.external",   // 额外添加的扫描路径
    "com.thirdparty.utils"    // 第三方工具包
})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

四、DI详解

        依赖注入是控制反转思想的具体实现,使用@Autowired注解。Springboot框架主要通过以下三种方式来实现依赖注入。

4.1 构造器注入

        通过类的构造方法来实现依赖注入,在对象创建时就完成所有必需依赖的注入。就像组建一个项目团队时,在团队成立的第一天就把所有核心成员(产品经理、开发工程师、测试工程师)一次性配齐。团队一旦成立,就具备了完整的工作能力。

@Service
public class OrderService {
    private final PaymentService paymentService;
    private final InventoryService inventoryService;
    
    // 构造器注入:Spring容器会自动识别并注入所需的依赖
    @Autowired
    public OrderService(PaymentService paymentService, InventoryService inventoryService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }
}
  • 优点:能清晰地看到类的依赖关系、提高了代码的安全性。
  • 缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。
  • 注意:如果只有一个构造函数,@Autowired注解可以省略。

在spring官方网站是推荐的这个方式,但是在真实的企业开发当中很多的项目组都会选择我们接下里要介绍的基于属性的方式注入,因为属性注入代码更加简洁,方便快速开发。如果说项目组对于这个代码的规范性要求比较高,就会选择这个构造器注入。

4.2 属性注入

        直接在字段上使用@Autowired注解,Spring通过反射机制完成注入。

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private InventoryService inventoryService;
}
  • 优点:代码简洁、方便快速开发。
  • 缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。

4.3 Setter方法注入

        通过setter方法来实现依赖注入,可以在对象创建之后再进行依赖注入。就像团队先成立,然后根据项目进展需要,陆续招聘或调配相关人员加入。团队在运行过程中可以动态调整成员构成。

@Service
public class OrderService {
    private PaymentService paymentService;
    private InventoryService inventoryService;
    
    // Setter方法注入
    @Autowired
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
    
    @Autowired
    public void setInventoryService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }
}
  • 优点:保持了类的封装性,依赖关系更清晰。
  • 缺点:需要额外编写setter方法,增加了代码量。

4.4解决同一类型多个Bean的冲突问题

       我们知道 @Autowired注解,默认是按照类型进行注入的。但是当Spring容器中存在多个相同类型的Bean时,使用@Autowired注解会遇到冲突问题。

        假设我们有一个支付接口和两个实现类:

public interface PaymentService {
    void pay();
}

@Service
public class AlipayService implements PaymentService {
    public void pay() {
        System.out.println("支付宝支付");
    }
}

@Service
public class WechatPayService implements PaymentService {
    public void pay() {
        System.out.println("微信支付");
    }
}

        当我们在其他类中注入时就会报错:

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService; // 报错:找到2个Bean,不知道用哪个
}

        错误信息:

NoUniqueBeanDefinitionException: No qualifying bean of type 'PaymentService' available: expected single matching bean but found 2: alipayService,wechatPayService

下面我们详细讲解三种解决方案:

4.4.1@Primary 

@Primary注解用于指定当有多个相同类型的Bean时,优先使用被标记的Bean。通常当某个Bean是默认的首选实现时,则选择这个方式。

@Service
@Primary  // 标记为主要的支付服务,当有多个PaymentService时优先使用这个
public class AlipayService implements PaymentService {
    public void pay() {
        System.out.println("支付宝支付(主要支付方式)");
    }
}

@Service
public class WechatPayService implements PaymentService {
    public void pay() {
        System.out.println("微信支付");
    }
}

注入时:

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService; // 自动使用AlipayService(因为有@Primary)
}

4.4.2 @Qualifier

@Qualifier注解通过Bean的名称来精确指定要注入哪个Bean。需要根据具体情况选择不同实现的场景。

@Service("alipay")  // 给Bean指定一个名称
public class AlipayService implements PaymentService {
    public void pay() {
        System.out.println("支付宝支付");
    }
}

@Service("wechat")  // 给Bean指定一个名称
public class WechatPayService implements PaymentService {
    public void pay() {
        System.out.println("微信支付");
    }
}

        注入时指定名称:

@Service
public class OrderService {
    @Autowired
    @Qualifier("alipay")  // 精确指定要注入的Bean名称
    private PaymentService paymentService;
}

        也可以直接在实现类上使用@Qualifier:

@Service
@Qualifier("alipay") //在类上指定
public class AlipayService implements PaymentService {
    // ...
}

@Service
@Qualifier("wechat")
public class WechatPayService implements PaymentService {
    // ...
}

4.4.3 @Resource

@Resource是Java标准注解(JSR-250),是javaE提供的注解并不是spring框架提供。@Autowired默认是按照类型注入,@Resource默认按名称进行注入。

需要注意三点规则:

  • 如果指定了name属性,则按名称查找Bean

  • 如果未指定name,则按字段名/方法名作为Bean名称查找

  • 如果按名称找不到,则回退到按类型查找

@Service
public class OrderService {
    @Resource(name = "alipayService")  // 按名称注入
    private PaymentService paymentService;
    
    // 或者使用字段名匹配(推荐写法)
    @Resource
    private PaymentService alipayService; // 会自动查找名为alipayService的Bean
}

五、总结

        控制反转与依赖注入是Spring框架的基石,它们通过将对象的创建和管理权从应用程序代码转移到IOC容器,有效降低了组件间的耦合度。在代码实现上面,文中介绍了多种方式。根据具体的业务需求选择合适的方案,或者组合使用以达到最佳的依赖管理效果。

最后感谢您的阅读,如有表述不准确或错误,欢迎批评指正!

2、机器人控制技术:阻抗/导纳控制与强化学习的融合 本文探讨了阻抗/导纳控制与强化学习在机器人控制中的融合应用。阻抗/导纳控制广泛应用于外骨骼和跟踪控制,通过改进方案提升建模误差下的鲁棒性;强化学习则为解决维度灾难、实现最优交互提供了有效途径,尤其在大输入空间、连续时间系统、冗余机器人及鲁棒控制中表现突出。结合近似器与合理奖励设计,强化学习可在无模型情况下实现高效控制。未来,两者融合有望推动更智能、更安全的机器人系统发展。 阅读详情

相关推荐

AMEsim不连续处理机制:仿真精度与效率的平衡艺术

本文深入解析AMEsim不连续处理机制在系统仿真中的应用,探讨如何平衡仿真精度与效率。通过液压系统仿真案例,详细介绍了事件检测算法、变步长求解器自适应策略及典型场景优化方法,帮助工程师有效应对仿真中的不连续性问题,提升仿真效率和准确性。

v4w5x6的博客 441

SpringBoot的控制反转(IOC)和依赖注入(DI)

控制反转和依赖注入

m0_47743353的博客 2463

VideoPose3D | 环境搭建

文章目录环境要求下载PyTorch基本步骤验证安装问题修复数据集设置Human3.6MCPN detections配置wget命令安装CPN评估环境测试问题测试报错 无法识别参数3 3 3 3卡在最后评估 主要参考:GitHub / facebookresearch / VideoPose3D 环境要求 Dependencies Make sure you have the followin...

D0 8655

Springboot 入门指南:控制反转和依赖注入的含义和实现方式

控制反转(Inversion of Control,简称 IoC)是一种设计原则,它的目的是降低代码之间的耦合度,提高模块化和可测试性。控制反转的含义是,将对象的创建、配置和管理交给一个外部容器来完成,而不是由对象自己或使用对象的类来完成。这样,对象就不需要知道或关心它们的依赖关系是如何被创建和维护的,只需要按照一定的规则和接口与容器进行交互即可。在 spring 框架中,IoC 容器就是负责实现控制反转的核心组件,它可以通过配置文件或注解的方式来管理应用程序中的各种 bean(即被容器管理的对象)。

TaloyerG的博客 1735

阿里奇门接口联调全流程详解:从沙箱自测到正式上线的保姆级攻略

本文详细解析阿里奇门接口联调的全流程,从沙箱自测到正式上线的关键步骤与避坑指南。涵盖环境配置、业务场景测试、跨团队协作、灰度发布及生产运维监控,帮助开发者高效完成API对接,确保供应链协同系统的稳定运行。特别适合首次接触奇门对接的技术负责人参考。

weixin_42535461的博客 416

Nuvoton OpenTitan开源安全芯片技术解析与应用

硬件安全模块(HSM)作为可信计算基的核心组件,其设计透明度和可验证性正成为行业焦点。RISC-V架构凭借开源特性,为构建可审计的安全芯片提供了新范式。OpenTitan项目通过开放Verilog源码和形式化证明,实现了从物理不可克隆函数(PUF)到分层安全启动的全栈透明。该方案在lowRISC Voyager开发板上实测显示,安全启动时间小于200ms,性能损耗仅7%,显著优于传统黑盒方案。目前该技术已应用于Chromebook和数据中心,其40nm工艺版本更将功耗降至5μA待机水平,为物联网和边缘计算提

weixin_36303807的博客 399

Spring Boot中的依赖注入和控制反转

通过自动配置、注解驱动和Java配置类,Spring Boot提供了一种优雅的方式来管理Spring应用中的Bean和依赖关系。理解和掌握Spring Boot中的依赖注入和控制反转,不仅可以提高代码的可维护性和可测试性,还能帮助开发者构建更灵活和可扩展的应用。通过依赖注入和控制反转,组件之间的依赖关系由容器管理,减少了代码的耦合性,使得代码更加模块化和可维护。通过Spring的配置文件和注解,可以很容易地添加或修改Bean的配置,增强了系统的可扩展性。通过构造函数注入,所有依赖在对象创建时就传递给对象。

技术研究中心 1291

网闸的基本配置

本文详细介绍了网闸的基本配置流程,包括物理连接与初始化、网络基础配置、核心数据交换策略配置、安全增强配置、管理与运维以及测试验证等关键步骤。网闸通过在物理隔离环境下建立"数据摆渡通道",实现特定业务数据的安全交换。配置时应遵循最小化、单向化、内容控制和审计原则,确保只开放必要通道,优先采用单向传输,进行内容安全检查并记录操作日志。不同厂商网闸的配置界面可能不同,但核心逻辑是相通的。

qq_39980997的博客 1843

SpringBoot控制反转(IOC)与依赖注入(DI)

本文介绍了SpringBoot三层架构及IOC/DI的核心概念。传统的三层架构(Controller、Service、Dao)中各层自行创建依赖对象,而IOC模式通过Spring容器管理对象生命周期。文章详细讲解了控制反转注解(@Component及其衍生注解@Controller、@Service、@Repository)和四种依赖注入方式(@Autowired、@Primary、@Qualifier、@Resource),展示了如何通过注解实现对象自动装配,取代传统new创建对象的方式,从而降低耦合度。

m0_72776581的博客 577

C# + YOLO 实时摄像头检测:Emgu CV + ONNX Runtime,30FPS+ 流畅运行

很多教程只给“单张图片推理”代码,一上摄像头就卡成 PPT(<5 FPS)。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 215

107.在 Vue 3 中使用 OpenLayers 实现视图联动功能

是一个非常强大的 Web 地图渲染库,支持多种地图数据格式和交互操作。在 Vue 3 中,我们可以利用。绑定到真实的 DOM 元素上,我们就可以用它们来初始化 OpenLayers 地图。来封装和管理 OpenLayers 地图的状态,从而更高效地开发地图应用。,即两个地图窗口共享同一个视图(View),从而实现同步缩放、拖动等操作。这可以确保 Vue 组件销毁时,OpenLayers 也正确销毁地图实例。,并且它们会同步缩放和拖动,达到地图联动的效果。这样,无论你拖动哪个地图,另一个都会同步变化。

小彭的博客 1938

Spring框架的控制反转和依赖注入

依赖注入的基本思想是:明确地定义组件接口,独立开发各个组件,然后根据组件的依赖关系组装运行。在使用依赖注入时,如果注入的是 Bean 对象,那么要求注入的 Bean 对象与被注入的 Bean 对象都需要 Spring IOC 容器来实例化。配置信息后,会通过反射方式调用实例的构造方法,如果是有参构造方法,可以在构造方法中传入所需的参数值,最后创建类对象。最主流的注入方法,这种注入方法简单、直观,它是在被注入的类中声明一个。被依赖的实例,构造方法可以是有参的或者是无参的。依赖注入通常有两种实现方式,一种是。

qq_63437335的博客 853

基于YOLOv11的农作物病虫害检测系统设计与实现

我们使用公开的IP102病虫害数据集作为基础,该数据集包含102种病虫害类别,覆盖水稻、小麦、玉米等多种主要农作物。图像数量:75,222张类别数:102图像分辨率:从640×480到4000×3000不等标注格式:PASCAL VOC格式此外,我们还收集了部分田间实际拍摄的图像以增强模型泛化能力。

YOLO 595

SpringBoot的IOC和DI学习

IOC通过@Repository、@Service、@RestController等注解,将对象的创建权交给容器,实现了控制权的转移;DI通过@Autowired注解,由容器自动将依赖对象注入到目标组件中,消除了组件间的手动依赖管理。两者共同作用,使案例中的UserController→UserService→UserDao三层架构松耦合,每层只需关注自身业务逻辑,无需关心依赖的创建,极大提升了代码的灵活性和可维护性。

TJ657的博客 1272

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

老版QQ原生表情gif动态

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

springboot的IOC和DI学习

然后,当某个 Bean(比如 UserService)依赖另一个 Bean(比如 UserRepository)时,容器会通过依赖注入(构造器、Setter、字段注入等方式),把 UserRepository 的 Bean 注入到 UserService 中。控制反转是一种设计原则,它反转了程序中对象创建和依赖传递的控制方式。在 Spring Boot 中,IOC(控制反转) 是核心设计思想,DI(依赖注入) 是 IOC 的具体实现手段,二者紧密结合,极大简化了应用开发中对象的管理与依赖关系的处理。

wklmm的博客 506

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

1813- 06.springboot的IOC和DI学习

IoC方式(反控):你去餐馆,直接对服务员说“我要一份鱼香肉丝”。厨师(容器)接到指令后,会从后厨(容器内部)准备好所有材料(依赖)并把做好的菜(对象)给你。在 Spring Boot 中:这个“餐馆系统”就是 Spring IoC 容器,它负责创建、组装、和管理所有应用对象(这些对象被称为Bean)。上面的餐馆例子中,厨师(容器)把做好的“鱼香肉丝”(依赖对象)注入到你的餐桌(需要依赖的对象)上,这个过程就是依赖注入。传统方式(正控):你想吃炒菜,你自己去菜市场买菜、洗菜、切菜、炒菜。

m0_68120176的博客 330

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

1808-《springboot》的IOC和DI学习

IOC(控制反转):是一种高级设计思想和目标。它的目标是解耦,将控制权从应用代码反转到外部。DI(依赖注入):是实现IOC思想的一种具体设计模式和技术手段。你可以不通过DI来实现IOC(比如用工厂模式),但在实践中,它们几乎总是成对出现。DI是实现IOC的最经典方式。

skfgo的博客 432

第5次课课堂作业-springboot的IOC和DI学习

概念:IOC(Inversion of Control)是一种软件设计原则,核心思想是将程序的控制权从应用程序代码转移到框架或容器中。传统编程中,代码直接调用依赖对象,而IOC通过外部机制(如依赖注入)管理对象创建和生命周期,实现解耦。核心特点:控制权转移:由框架/容器管理对象创建和依赖关系,而非开发者手动控制。解耦:组件间依赖关系由外部配置,减少代码直接耦合。依赖注入(DI):IOC的一种实现方式,通过构造函数、属性或接口注入依赖对象。

A1786004587的博客 561

黑马JAVAWeb-03 SpringBootWeb-分层解耦-三层架构-@SpringBootApplication注解-IOC控制反转-DI依赖注入

4. (@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan)是 Spring Boot 的核心注解,共同构成了 @SpringBootApplication 注解的底层实现,也是 Spring Boot 实现 “自动配置” 和 “快速开发” 的关键。4.2 EnableAutoConfiguration 实现自动配置(模拟第三方 Starter)5.1 三种注入方式 - 主要还是用属性注入。

Tianwen55的博客 1394

《springboot的IOC和DI学习》

IOC 与 DI 的关系总结:IOC 是 “控制反转” 的思想,回答了 “谁来控制资源”(容器而非开发者);DI 是 “依赖注入” 的手段,回答了 “容器如何给对象提供资源”(自动注入依赖);二者本质是 “思想与实现” 的关系,共同实现了 Spring 中对象的解耦和自动化管理。

Vacuumtj的博客 802

5-《springboot的IOC和DI学习》

这篇文章围绕 Spring Boot 中的 IOC(控制反转)和 DI(依赖注入)两大核心概念展开控制反转指对象创建和对象间依赖关系的控制权,从开发者手动控制转移到Spring容器手中。传统开发中需要开发者用new创建对象,而IOC模式下,这部分工作由Spring容器承担。依赖注入是IOC思想的具体实现,指Spring容器在创建Bean时,自动将其依赖的其他Bean注入进来,建立依赖关系。

2201_75572472的博客 442

06-《springboot的IOC和DI学习》

指由外部容器在运行期,将依赖对象被动地设置到目标对象(例如,将 UserRepository 对象“注入”到 UserService 的成员变量中)。在一个对象内部,如果你需要另一个对象(依赖),你会自己(在代码中显式地)使用 new 关键字来创建它。控制反转(IOC)这个思想很好,但需要一种具体的机制来实现它。(最推荐的方式,因为它保证了依赖在对象创建时就被完整设置,且不可变,易于测试)。**DI(依赖注入)**是手段、是具体实现、是设计模式。**IOC(控制反转)**是目的、是思想、是设计原则。

m0_65977576的博客 288

二、springboot的IOC和DI学习

Compoment:标记一个类为 ​Spring 管理的组件(Bean)​,Spring 会自动扫描并创建该类的实例,纳入 IoC 容器(控制反转容器)中管理。@Autowired:实现 ​自动依赖注入​(DI),Spring 会自动查找匹配的 Bean 并注入到目标位置(如字段、构造函数、方法)。IOC:控制反转是一种设计原则或设计思想。它的核心是将程序的控制权反转。DI:依赖注入是实现控制反转这一思想的最主要、最常用的具体技术模式。

cc1217882708的博客 712

第5次作业——springboot的IOC和DI学习

1.1、理论定义:IOC 是一种设计思想,其核心是 将对象的创建权、生命周期管理和依赖关系的控制权从业务逻辑代码中转移到外部容器(如 Spring 的 IoC 容器),实现了 “控制权” 的反转。1.2、传统开发与 IOC 的对比:传统开发:开发者需要在代码中手动通过 new 关键字创建对象,并维护对象之间的依赖关系(例如 A a = new A();此时,对象的创建和依赖管理完全由开发者控制。

wwwQiu_的博客 455

(原创)实现springboot分层解耦技术

(原创) springboot实现分层解耦的方案(原创) springboot实现分层解耦的方案。

qq_50631755的博客 949
上一篇: springboot入门必看:三层架构核心解析
下一篇: SpringBoot开发规范——Restful
我叫张小白。
博客等级 码龄3年 43粉丝 127原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值