IoC 思想简单而深邃

一、序言

本文跟大家聊聊 IoC 这一简单而深邃的思想。

二、依赖倒置原则

软件工程理论中共有六大设计原则:

  1. 单一职责原则:不存在多于一个的因素导致类的状态发生变更,即一个类只负责一项单一的职责。
  2. 里氏替换原则:基类出现的地方都可以用其子类进行替换,而不会引起任何不适的问题。
  3. 接口隔离原则:客户端不应该依赖于其不需要的接口,类之间的依赖关系应该建立在最小的接口之上。
  4. 迪米特法则:一个对象对其他对象有最少的了解。
  5. 开闭原则:软件设计对于扩展是开发的,即模块的行为是可以扩展的。软件设计对于修改是关闭的,即模块的行为是不可修改的。
  6. 依赖倒置原则:高层次的模块不应该依赖于低层次的模块,都应该依赖于抽象。

今天我们只讨论依赖倒置原则。上面对于依赖倒置原则的绕口令我们先暂时放下。

场景假设:一个人通过一种交通工具上下班。

  1. 若不遵循依赖倒置原则,实现方案如下:

    居住地离公司较近时:

    // 自行车类
    public class Bike {
    
        public void go() {
            System.out.println("骑自行车");
        }
    }
    
    public class Person {
    
        // 自行车
        private Bike bike;
    
        // 构造器
        public Person() {
            this.bike = new Bike();
        }
    
        // 上班
        public void goToWork() {
            bike.go();
        }
        
    }
    

    居住地离公司较远时:

    // 公交车类
    public class Bus {
        public void go() {
            System.out.println("乘坐公交车");
        }
    }
    
    public class Person {
    
        // 公交车
        private Bus bus; 
    
        // 构造器
        public Person() {
            this.bus = new Bus();
        }
    
        // 上班
        public void goToWork() {
            bus.go();
        }
    }
    

    不遵循依赖倒置原则时,我们发现了一个巨大的问题:每换一次交通工具,Person 类几乎是重构了一遍。

  2. 遵循依赖倒置原则,实现方案如下:

    交通工具会有很多,我们将其进行一次抽象:

    // 交通工具接口
    public interface Vehicle {
        // 出发
        void go();
    }
    

    居住地离公司较近时:

    // 自行车类
    public class Bike implements Vehicle {
    
        @Override
        public void go() {
            System.out.println("骑自行车");
        }
    }
    
    public class Person {
    
        // 此处放抽象接口
        private Vehicle vehicle;
    
        // 构造器
        public Person() {
            // 抽象接口的实现类是自行车
            this.vehicle = new Bike();
        }
    
        // 上班
        public void goToWork() {
            vehicle.go();
        }
    
    }
    

    居住地离公司较远时:

    // 公交车类
    public class Bus implements Vehicle {
        @Override
        public void go() {
            System.out.println("乘坐公交车");
        }
    }
    
    public class Person {
    
        // 此处放抽象接口
        private Vehicle vehicle;
    
        // 构造器
        public Person() {
            // 抽象接口的实现类是公交车
            this.vehicle = new Bus();
        }
    
        // 上班
        public void goToWork() {
            vehicle.go();
        }
    }
    

    当我们采用依赖倒置原则实现方案时,可以发现除了构造器中需要修改,其他部分不需要做任何的修改。

现在我们重新看一下依赖倒置原则那段绕口令。高层次的模块不应该依赖于低层次的模块,即高层次模块与低层次模块应该解耦,就如同 Person 类和 Bike/Bus 类一样。如果 Person 类中直接依赖 Bike/Bus 类就会出现高耦合。都应该依赖于抽象指的是:为了解耦,高层次的模块应该依赖于低层次模块的抽象而不是具体的低层次模块。就如同 Person 类应该依赖 Vehicle 抽象接口。

三、IoC 思想

当我们遵循依赖倒置原则开发时虽然解决了大部分问题,但是我们发现依旧还存在一些问题:

public class Person {

    private Vehicle vehicle;

    public Person() {
        // 此处每次仍需要修改
        this.vehicle = new Bus();
    }

    public void goToWork() {
        vehicle.go();
    }
}

上面的问题是: Person 类依旧需要手动的创建 Bike 或 Bus 对象。有没有一种方式将这种手动的方式变成自动管理,从而进一步实现解耦呢?解决方案就是采用 IoC 思想。

IoC,全称为 Inversion of Control,中文名为“控制反转”,是一种设计思想。其核心思想是:将对象的创建权、管理权移交给容器,而不是开发人员。

Spring 已经将 IoC 思想具象化,我们以 Spring 中的 IoC 容器为例重新分析上述的例子。

// 自行车类
@Component
public class Bike implements Vehicle {

    @Override
    public void go() {
        System.out.println("骑自行车");
    }
}

@Component
public class Person {

    // 此处放抽象接口
    @Resource
    private Vehicle vehicle;

    // 构造器
    public Person() {
    }

    // 上班
    public void goToWork() {
        vehicle.go();
    }

}

从上面的代码中我们可以看出:在 Person 类中我们使用 @Resource注解将 Vehicle 对象的赋值交由 IoC 容器。容器创建 Bike 对象之后将其引用赋给了上述的 vehicle 变量。至此,对象与对象之间的完全解耦实现了。

四、IoC 思想工作流程的具象化未命名文件 (7).png

  1. 开发人员向 IoC 容器声明需要的对象
  2. IoC 容器维护所有对象之间的关系,以及对象的创建时机
  3. 开发人员需要对象时直接从 IoC 容器中获取(获取到的对象与其他对象的关系已由 IoC 容器维护好)

往期推荐

  1. JDK 动态代理
  2. ThreadLocal
  3. HashMap 源码分析(三)
  4. Spring 三级缓存
  5. RBAC 权限设计(二)
<think>好的,我现在需要回答用户关于Spring Boot是否包含IoC思想以及其实现原理的问题。首先,我得确认用户的基本需求,他们可能已经知道Spring框架的IoC,但想了解Spring Boot在这方面的继承和具体实现。 根据提供的引用内容,引用[1]提到SpringIoC实现原理,特别是依赖注入(DI)作为IoC的一种实现方式。引用[2]则指出Spring Boot成功的原因之一是对IoC和AOP的应用,所以可以确定Spring Boot确实包含IoC思想。引用[3]展示了传统的XML配置Bean的方式,这可能与Spring Boot的自动配置形成对比。 接下来,我需要组织回答结构。首先明确回答Spring Boot确实包含IoC,然后解释其实现原理,包括自动配置、组件扫描和条件化配置。需要对比传统SpringSpring Boot的不同之处,比如减少配置的工作量。同时,要结合用户提到的实现原理,可能涉及ApplicationContext、Bean定义等概念。 还要注意用户可能对底层机制感兴趣,比如自动配置是如何实现的,可能涉及@SpringBootApplication注解的组合功能,如@EnableAutoConfiguration、@ComponentScan。需要解释这些注解的作用,以及Spring Boot如何利用spring.factories文件进行自动配置类的加载。 另外,用户可能想知道Spring Boot如何管理Bean的生命周期,这可以联系到ApplicationContext的作用,比如创建、装配、管理Bean。同时,条件化配置如@ConditionalOnClass等注解的使用,说明Spring Boot如何根据环境动态决定Bean的创建,这可以展示其智能化的配置机制。 需要确保回答中提到的技术点都有依据,比如引用中的内容。例如,引用[2]提到Spring Boot成功归功于IoC和AOP,所以在回答中要突出这一点。同时,可能引用[3]中的XML配置例子来对比Spring Boot的自动配置,说明简化配置的过程。 在生成相关问题部分,需要考虑用户可能的后续疑问,比如自动配置原理、如何自定义Bean、与Spring框架的IoC区别等。这些问题需要自然延伸当前回答的内容,帮助用户深入理解。 最后,检查是否符合系统级指令:使用中文,数学公式正确(虽然这里可能用不上),引用标识正确添加。确保回答结构清晰,分点说明实现原理,代码示例正确展示注解和配置类,并且相关问题具有针对性。</think>Spring Boot不仅完全继承了Spring框架的IoC思想,还通过自动化配置机制将其实现推向新高度。以下是具体实现原理分析: ### 一、Spring Boot IoC实现原理 1. **自动配置引擎** 通过`@SpringBootApplication`注解组合实现: ```java @SpringBootConfiguration @EnableAutoConfiguration // 激活自动配置 @ComponentScan // 组件扫描 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 自动配置类通过`META-INF/spring.factories`文件注册,例如: ``` org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration ``` 2. **条件化装配机制** 使用`@Conditional`系列注解实现智能决策: - `@ConditionalOnClass`:类路径存在指定类时生效 - `@ConditionalOnMissingBean`:容器不存在指定Bean时生效 - `@ConditionalOnProperty`:配置参数满足条件时生效 3. **组件扫描增强** 在传统Spring的`@ComponentScan`基础上,通过自动路径推导实现零配置扫描: ``` com.example.application └── Application.java // 主类所在包自动成为扫描根路径 ``` ### 二、与传统Spring的对比 | 特性 | Spring Framework | Spring Boot | |---------------------|------------------------|--------------------------| | 配置方式 | XML/JavaConfig显式声明 | 约定优于配置 | | Bean发现机制 | 手动定义 | 自动扫描+条件装配 | | 依赖管理 | 手动指定版本 | starter POM统一管理 | | 典型配置量 | 50+行基础配置 | 0行基础配置 | ### 三、核心运行流程 1. 创建`ApplicationContext`容器(默认使用`AnnotationConfigServletWebServerApplicationContext`) 2. 加载所有`@Configuration`配置类 3. 执行自动配置: - 解析`spring-autoconfigure-metadata.properties`元数据 - 过滤符合条件的`AutoConfiguration`类 4. 实例化并装配所有Bean(通过构造器注入或字段注入) 5. 执行`CommandLineRunner`等生命周期回调 [^1]: Spring Boot的自动配置机制实质上是IoC容器的高级应用,通过条件判断动态注册Bean定义 [^2]: 启动类中`SpringApplication.run()`方法触发整个IoC容器初始化流程
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值