IoC设计思想
解耦
解耦是面向对象设计中永恒的主题,所有的设计原则都在围绕它。解耦就是将软件中可能会变化的部分相互间进行隔离,使得某个部分变化不影响其它部分。
主要目标是实现下列四种特性:
- 可测试性
- 可维护性
- 可扩展性
- 可复用性
职责分离
职责分离是实现程序解耦的一种常用手段。设计模式六大原则之一的单一职责原则(SRP)指出,就一个类而言,应该只专注于做一件事和仅有一个引起它变化的原因。将一个复杂的功能点拆分成多个类,使得每个类只负责一件事。
但是当多个对象共同完成一个功能时,相互之间就需要进行协作。协作就会产生依赖,就会导致耦合,这是不可避免的,唯一能做的就是如何使得这种依赖带来的耦合度更低。
依赖包括两种:
- 引用依赖:一旦进行了声明就产生了这种依赖,尽量使用接口而不使用具体类声明。
- 实例依赖:对象总是需要创建,哪个类使用了new操作符,这个类就依赖于被创建类及其实例化细节。很多设计模式都是在努力改善这点,IOC是其中一种。
对象创建
一般来说,创建一个有依赖的对象有下列几种形式:
一. 直接使用NEW创建依赖对象
优点:简单直接,代码量少
缺点:需要了解依赖对象的创建细节,无法对依赖对象进行共享。
|
|
二. 由调用者创建依赖对象
优点:服务类无任何依赖
缺点:调用者需要负责创建其不直接使用的类,职责错误
|
|
三. 通过工厂获取依赖对象
优点:只有工厂对象依赖创建细节,符合单一职责。可以控制依赖对象的实例个数。
缺点:需要额外的工厂类,增加代码量。
|
|
IoC容器核心概念
由于上面几种创建对象的方法都有明显缺点,不利于大型工程的开发,因而出现了IoC容器。
控制反转(Inversion of Control) 就是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。
IoC容器结合工厂模式与依赖注入,将对象创建统一至容器中,所有的创建细节以统一的形式配置与管理。
IoC容器组成部分:
- 配置文件——进行对象的定义,声明对象的创建细节(Bean定义)
- Bean——对应配置文件中具体类的实例(可能被代理过)
- IOC容器——负责所有Bean的生命周期管理,并为客户端提供获取Bean的接口
- 客户端——通过IOC容器获取Bean
优点:
- 容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码)
- 在创建实例的时候不需要了解其中的细节 缺点:
- 严重依赖IOC容器
- 脱离IOC容器创建对象将非常困难
- 容器外对象访问容器中的实例时,将依赖容器的特定API
- 基本上只能将对象配置为单例,其它场景很难使用
SpringIoC容器
组成
SpringIoC容器主要接口是BeanFactory和ApplicationContext,实际上就是结合这两个组件共建了一个 bean 关系网。
BeanFactory管理所有的Bean定义与Bean实例,提供查找Bean的接口。
ApplicationContext是包括了容器事件、国际化消息、资源加载器的一个BeanFactory的扩展,使其更易于让应用程序使用。
创建方式
一、通过构造方法创建<bean id="person" class="com.nd.Person"></bean>
二、通过静态工厂方法创建<bean id="person" class="com.nd.PersonStaticFactory" factory-method="createPerson"></bean>
三、通过实例工厂方法创建<bean id="personFactory" class="com.nd.PersonFactory"></bean><bean id="person" factory-bean="personFactory" factory-method="createPerson"></bean>
四、注解方式,通过反射调用实例工厂创建
注入方式
一、构造方法注入
二、setter方法注入
三、@Autowired注解
作用域
- singleton: 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
- prototype: 原型模式,每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
- request: 对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
- session:对于一次HTTP会话,session作用域的Bean将只生成一个实例,这意味着,在同一次HTTP会话内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
- global session: 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
Bean生命周期
Bean生命周期BeanPostProcessor在Bean创建过程中调用,对Bean实例进行处理。
BeanFactoryPostProcessor在所有Bean注册后,实例化之前调用,对BeanDefinition进行加工。
特定接口
- BeanFactoryAware:可以获取到BeanFactory1234public interface BeanFactoryAware extends Aware {void setBeanFactory(BeanFactory beanFactory) throws BeansException;}
- ApplicationContextAware:可以获取到ApplicationContext对象12345public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}
InitializingBean:定义初始化bean时的操作
DisposableBean:定义销毁bean时的操作