什么是IOC
简单的说:
IOC就是构建和管理依赖的容器
咱们暂且放下控制反转这个拗口的词。
没有IOC的年代
在IOC诞生之前,我们是如何写业务代码的呢? 如下面所示:
java
体验AI代码助手
代码解读
复制代码
public class A {
}
public class B {
private A a = new A();
}
当然上述是一段伪代码。
维护的困局
代码能按业务拆分成多个不同的类已经是不错的写法了,但是到了要增加逻辑的时候就麻烦了。
你得对A或者B进行修改,这样维护起来还是不够优雅的。
于是你对此进行了一些设计:
java
体验AI代码助手
代码解读
复制代码
interface A {
void method();
}
public class AImpl implents A {
void method(){
// todo
}
}
public class B {
private final A a;
public B(A a){
this.a = a; // 传入对应的实现
}
}
这样在需要新增逻辑的时候只要写一个新的实现类就行了,不必回去修改AImpl了。
依赖处理的困局
到这一步我们发现B对A存在依赖,这个依赖由外部传入,也就是说新增逻辑我们必须得修改传入依赖的地方。
java
体验AI代码助手
代码解读
复制代码
new B(new AImpl());
这里可能就会修改为:
new B(new BImpl());
上面暴露了2个比较明显的问题:
- 每次调整都可能会修改依赖 => 依赖的管理问题
- 每次都是new一个依赖进去,非常浪费内存 => 依赖的构建问题
这时,你能设计出一个办法处理这种问题吗?
IOC的诞生
分析
我们一步一步来分析下这2个问题,如果换做是人来处理这些东西会怎么处理呢?
第一步,我们必须得知道哪个类依赖哪个类,也就是说要有一个提供依赖信息的地方。 第二步,得知依赖信息了,我们就得new个出来给他。
那么我们定义一下这2步,第一步可以称之为依赖信息的获取,第二步可以称之为依赖的管理。
如何处理问题
- 依赖信息的获取
- XML配置形式
- Java注解方式
- 其他形式
信息可以记录在任何地方,任何形式,但我们得找到一个最适应当下的方式。 聪明的你应该已经想到了,我们先定义一个接口,做成一个策略模式,不同形式的使用不同的加载策略。
- 依赖的管理
- 实例化
- 依赖处理
- 其他前置后置处理
我们可以直接使用反射来进行实例化和依赖处理,当然实例化和依赖处理最好也留好接口。
这里我就不写代码演示了,目的是要大家明白IOC的主要2个功能即:
- 依赖的构建
- 依赖的管理
Spring提供的IOC容器
Spring提供了2个IOC容器:
- BeanFactory
基础IOC能力,只有Bean的构建和管理
- ApplicationContext
基于BeanFactory,增加了其他功能
简而言之,ApplicationContext提供了更多的可用可扩展的功能。
BeanFactory如何管理依赖
DefaultListableBeanFactory 类是BeanFactory的一个默认实现类,有完整的bean构建管理功能。
java
体验AI代码助手
代码解读
复制代码
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(AreaApi.class); // 转为统一的Bean的定义信息类
defaultListableBeanFactory.registerBeanDefinition("A",rootBeanDefinition); // 向容器中注入定义 其实就是添加进一个map里
defaultListableBeanFactory.getBean("A");
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256); // 这里就是存放所有bean定义的地方 是DefaultListableBeanFactory的一个属性。
ApplicationContext如何管理依赖
AnnotationConfigApplicationContext <= GenericApplicationContext <= AbstractApplicationContext <= ApplicationContext
通过整个继承链来看,最终是实现了ApplicationContext的。
java
体验AI代码助手
代码解读
复制代码
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ValidatorConfiguration.class);
ValidatorConfiguration bean = annotationConfigApplicationContext.getBean(ValidatorConfiguration.class);
其实追寻源码可以看到在==GenericApplicationContext==类中是加载了 DefaultListableBeanFactory
java
体验AI代码助手
代码解读
复制代码
public GenericApplicationContext() {
this.customClassLoader = false;
this.refreshed = new AtomicBoolean();
this.beanFactory = new DefaultListableBeanFactory(); // 构造方式中 直接 new 了基础IOC容器
}
总结
整个IOC的流程可以归纳为:
获取bean的信息 => 保存起来 => 实例化 => 处理依赖 => 返回实例
其余功能无非是在这几个流程上加前置或者后置处理。
在最后解释一下控制反转怎么理解:
其实就是由人管理依赖也就是new的过程交给了程序,控制权交出去了,也就是控制权反转了。
spring的源码过于庞大了,如果有兴趣可以自行研究,这里我们只关注Spring最重要的部分就可以了。