SpringIOC实现原理

1. 概述

IOC(Inversion of Control)控制反转,也称为DI(Dependency Injection)依赖注入。所谓IOC ,就是把原先代码里需要开发者实现的对象创建和关系依赖,反转交给SpringIOC容器管理对象的生命周期和对象之间的依赖关系。

Spring通过配置文件描述Bean及Bean之间的依赖关系(或者是注解@annotation),利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。

Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配Bean之间的依赖关系,最后将Bean保存到Spring容器中的Bean缓存池中,其中Bean缓存池是由ConcurrentHashMap实现

SpringIOC实现原理_第1张图片

2. 依赖倒置

假设我们设计一辆汽车:先设计轮子,然后根据轮子大小设计底盘,接着根据底盘设计车身,最后根据车身设计好整个汽车。这里就出现了一个依赖关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子

这样的设计看起来没问题,但是可维护性却很低。假设设计完工之后,上司却突然说根据市场需求的变动,要我们把车子的轮子设计都改大一码。这下我们就蛋疼了:因为我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改。

同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改——整个设计几乎都得改!我们现在换一种思路。我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘, 底盘依赖车身, 车身依赖汽车

这时候,上司再说要改动轮子的设计,我们就只需要改动轮子的设计,而不需要动底盘,车身,汽车的设计了。这就是依赖倒置原则——把原本的上层依赖底层倒置过来,变成底层依赖上层。上层决定需要什么,底层就去实现这样的需求,而上层并不关注底层怎么实现的。这样就不会出现前面的牵一发而动全身的情况。

3. 控制反转

控制反转是依赖倒置原则的一种代码设计的思路,具体采用的方法是依赖注入(Dependency Injection)。所谓依赖注入,上层控制底层,底层类作为参数传入上层类

4. 常用容器

4.1 BeanFactory

BeanFactory是Spring框架的基础设施,是IOC容器的基础接口,所有的容器都是从它这里继承实现而来。BeanFactory作为SpringIOC容器,为了能够明确描述各个对象间的依赖关系,Spring提供了三种管理方式:

  1. 在XML中进行显式配置。
  2. 在Java中进行显式配置。
  3. 注解方式。

Spring提供了三种注入方式

  • 构造方法注入。
  • setter方法注入。
  • 注解方式注入。
SpringIOC实现原理_第2张图片

4.2 ApplicationContext

ApplicationContext是Spring提供的一个高级的IOC容器,面向使用Spring框架的开发者,它除了能够提供IOC容器的基本功能外,还为用户提供了以下的附加服务:

  • BeanFactory:能够管理和装配Bean。
  • ResourcePatternResolver:能够加载资源文件。
  • MessageResource:能够实现国际化等功能。
  • ApplicationEventPublisher:能够注册监听器,实现监听机制。

Spring自带多种类型的应用上下文:

  1. AnnotatinonConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
ApplicationContext context = new AnnotatinonConfigApplicationContext(com.cmos.DemoConfig.class);
  1. AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载SpringWeb应用上下文。
  2. ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
ApplicationContext context = new ClassPathXmlApplicationContext("demo.xml");
  1. FileSystemXmlApplicationContext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
ApplicationContext context = new FileSystemXmlApplicationContext("c:/demo.xml");
  1. XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。

5. Bean的作用域

  • singleton:这种Bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个Bean的实例,单例的模式由BeanFactory自身来维护。
  • prototype:原形范围与单例范围相反,为每一个Bean请求提供一个实例。
  • request:在请求Bean范围内会为每一个来自客户端的网络请求创建一个实例,在请求完成以后,Bean会失效并被垃圾回收器回收。
  • session:与请求范围类似,确保每个Session中有一个Bean的实例,在Session 过期后,Bean会随之失效。
  • global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多 portlet。如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在global-session 中。全局作用域与Servlet中的Session 作用域效果相同。

6. Bean的生命周期

  1. Spring对Bean实例化;
  2. Spring将值和Bean的引用注入到Bean对应的属性中;
  3. 如果Bean实现了BeanNameAware接口,Spring将调用setBeanName()方法传递Bean的ID到BeanFactory中;
  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactroy()方法,将BeanFactory容器实例传入,便于Bean够获取配置他们的BeanFactory的引用
  5. 如果Bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将Bean所在应用上下文的引用传进来,便于bean获取它所在的Spring容器
  6. 如果Bean实现了BeanPostProcessor接口,Spring将调用postProcessBeforeInitialization()方法,该方法在Bean初始化之前调用。如果Bean在Spring配置文件中配置了init-method属性,该方法将会自动调用。
  7. 如果Bean实现了InitializingBean接口,Spring将调用它的afterPropertiesSet()方法,当Bean的所用属性被设置完成之后调用该方法;
  8. 如果Bean实现了BeanPostProcessor接口,Spring将调用它的postProcessAfterInitialization()方法,在Bean初始化完成之后调用;
  9. 此时Bean准备就绪;
  10. 如果Bean实现了DisposableBean接口,spring将调用它的destory()方法。如果Bean在Spring配置文件中配置了destory-method属性,该方法将会自动调用。
SpringIOC实现原理_第3张图片

你可能感兴趣的:(SpringIOC实现原理)