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实现。
2. 依赖倒置
假设我们设计一辆汽车:先设计轮子,然后根据轮子大小设计底盘,接着根据底盘设计车身,最后根据车身设计好整个汽车。这里就出现了一个依赖关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。
这样的设计看起来没问题,但是可维护性却很低。假设设计完工之后,上司却突然说根据市场需求的变动,要我们把车子的轮子设计都改大一码。这下我们就蛋疼了:因为我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改。
同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改——整个设计几乎都得改!我们现在换一种思路。我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘, 底盘依赖车身, 车身依赖汽车。
这时候,上司再说要改动轮子的设计,我们就只需要改动轮子的设计,而不需要动底盘,车身,汽车的设计了。这就是依赖倒置原则——把原本的上层依赖底层倒置过来,变成底层依赖上层。上层决定需要什么,底层就去实现这样的需求,而上层并不关注底层怎么实现的。这样就不会出现前面的牵一发而动全身的情况。
3. 控制反转
控制反转是依赖倒置原则的一种代码设计的思路,具体采用的方法是依赖注入(Dependency Injection)。所谓依赖注入,上层控制底层,底层类作为参数传入上层类。
4. 常用容器
4.1 BeanFactory
BeanFactory是Spring框架的基础设施,是IOC容器的基础接口,所有的容器都是从它这里继承实现而来。BeanFactory作为SpringIOC容器,为了能够明确描述各个对象间的依赖关系,Spring提供了三种管理方式:
- 在XML中进行显式配置。
- 在Java中进行显式配置。
- 注解方式。
Spring提供了三种注入方式:
- 构造方法注入。
- setter方法注入。
- 注解方式注入。
4.2 ApplicationContext
ApplicationContext是Spring提供的一个高级的IOC容器,面向使用Spring框架的开发者,它除了能够提供IOC容器的基本功能外,还为用户提供了以下的附加服务:
- BeanFactory:能够管理和装配Bean。
- ResourcePatternResolver:能够加载资源文件。
- MessageResource:能够实现国际化等功能。
- ApplicationEventPublisher:能够注册监听器,实现监听机制。
Spring自带多种类型的应用上下文:
- AnnotatinonConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
ApplicationContext context = new AnnotatinonConfigApplicationContext(com.cmos.DemoConfig.class);
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载SpringWeb应用上下文。
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
ApplicationContext context = new ClassPathXmlApplicationContext("demo.xml");
- FileSystemXmlApplicationContext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
ApplicationContext context = new FileSystemXmlApplicationContext("c:/demo.xml");
- 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的生命周期
- Spring对Bean实例化;
- Spring将值和Bean的引用注入到Bean对应的属性中;
- 如果Bean实现了
BeanNameAware
接口,Spring将调用setBeanName()方法传递Bean的ID到BeanFactory中; - 如果Bean实现了
BeanFactoryAware接口
,Spring将调用setBeanFactroy()方法,将BeanFactory容器实例传入,便于Bean够获取配置他们的BeanFactory的引用; - 如果Bean实现了
ApplicationContextAware
接口,Spring将调用setApplicationContext()方法,将Bean所在应用上下文的引用传进来,便于bean获取它所在的Spring容器; - 如果Bean实现了
BeanPostProcessor
接口,Spring将调用postProcessBeforeInitialization()方法,该方法在Bean初始化之前调用。如果Bean在Spring配置文件中配置了init-method属性,该方法将会自动调用。 - 如果Bean实现了
InitializingBean
接口,Spring将调用它的afterPropertiesSet()方法,当Bean的所用属性被设置完成之后调用该方法; - 如果Bean实现了
BeanPostProcessor
接口,Spring将调用它的postProcessAfterInitialization()方法,在Bean初始化完成之后调用; - 此时Bean准备就绪;
- 如果Bean实现了
DisposableBean
接口,spring将调用它的destory()方法。如果Bean在Spring配置文件中配置了destory-method属性,该方法将会自动调用。
网友评论