咸鱼开发修炼之路

IoC设计思想与springIoC容器介绍

IoC设计思想

解耦

解耦是面向对象设计中永恒的主题,所有的设计原则都在围绕它。解耦就是将软件中可能会变化的部分相互间进行隔离,使得某个部分变化不影响其它部分。
主要目标是实现下列四种特性:

  • 可测试性
  • 可维护性
  • 可扩展性
  • 可复用性
940cbaa7.png

职责分离

职责分离是实现程序解耦的一种常用手段。设计模式六大原则之一的单一职责原则(SRP)指出,就一个类而言,应该只专注于做一件事和仅有一个引起它变化的原因。将一个复杂的功能点拆分成多个类,使得每个类只负责一件事。

但是当多个对象共同完成一个功能时,相互之间就需要进行协作。协作就会产生依赖,就会导致耦合,这是不可避免的,唯一能做的就是如何使得这种依赖带来的耦合度更低。
依赖包括两种:

  • 引用依赖:一旦进行了声明就产生了这种依赖,尽量使用接口而不使用具体类声明。
  • 实例依赖:对象总是需要创建,哪个类使用了new操作符,这个类就依赖于被创建类及其实例化细节。很多设计模式都是在努力改善这点,IOC是其中一种。

对象创建

一般来说,创建一个有依赖的对象有下列几种形式:
一. 直接使用NEW创建依赖对象

优点:简单直接,代码量少

缺点:需要了解依赖对象的创建细节,无法对依赖对象进行共享。

1
2
3
4
5
6
7
8
9
10
class UserService {
private UserDao userDao;
public UserService() {
userDao = new UserDao();
}
}
class UserDao {
}

二. 由调用者创建依赖对象

优点:服务类无任何依赖

缺点:调用者需要负责创建其不直接使用的类,职责错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//由调用者创建依赖对象
public class Demo3 {
public static void main(String[] args) {
UserDao userDao = new UserDao();
new UserService(userDao);
}
}
class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
class UserDao {
}

三. 通过工厂获取依赖对象

优点:只有工厂对象依赖创建细节,符合单一职责。可以控制依赖对象的实例个数。

缺点:需要额外的工厂类,增加代码量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class UserService {
private UserDao userDao;
public UserService() {
userDao = UserDaoFactory.getInstance().get();
}
}
class UserDao {
}
class UserDaoFactory {
private static UserDaoFactory instance = new UserDaoFactory();
public static UserDaoFactory getInstance() {
return instance;
}
private UserDao userDao = new UserDao();
public UserDao get() {
return userDao;
}
}

IoC容器核心概念

由于上面几种创建对象的方法都有明显缺点,不利于大型工程的开发,因而出现了IoC容器。
控制反转(Inversion of Control) 就是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。
IoC容器结合工厂模式与依赖注入,将对象创建统一至容器中,所有的创建细节以统一的形式配置与管理。

765b3154.png

IoC容器组成部分:

  1. 配置文件——进行对象的定义,声明对象的创建细节(Bean定义)
  2. Bean——对应配置文件中具体类的实例(可能被代理过)
  3. IOC容器——负责所有Bean的生命周期管理,并为客户端提供获取Bean的接口
  4. 客户端——通过IOC容器获取Bean

优点

  • 容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码)
  • 在创建实例的时候不需要了解其中的细节ae7967fd.png 缺点
  • 严重依赖IOC容器
  • 脱离IOC容器创建对象将非常困难
  • 容器外对象访问容器中的实例时,将依赖容器的特定API
  • 基本上只能将对象配置为单例,其它场景很难使用

SpringIoC容器

组成

210af86a.png

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>
四、注解方式,通过反射调用实例工厂创建

注入方式

一、构造方法注入
33c0a767.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {
private B b;
private C c;
private int value;
public A(B b, C c, int value) {
this.b = b;
this.c = c;
this.value = value;
}
}
class B {
}
class C {
}

二、setter方法注入
96fa3fd7.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A {
private B b;
private C c;
private int value;
public void setB(B b) {
this.b = b;
}
public void setC(C c) {
this.c = c;
}
public void setValue(int value) {
this.value = value;
}
}
class B {
}
class C {
}

三、@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生命周期

87af16a5.png

Bean生命周期BeanPostProcessor在Bean创建过程中调用,对Bean实例进行处理。

1
2
3
4
5
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;
Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
}

BeanFactoryPostProcessor在所有Bean注册后,实例化之前调用,对BeanDefinition进行加工。
1
2
3
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

特定接口

  • BeanFactoryAware:可以获取到BeanFactory
    1
    2
    3
    4
    public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
    }
  • ApplicationContextAware:可以获取到ApplicationContext对象
    1
    2
    3
    4
    5
    public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
    }
  • InitializingBean:定义初始化bean时的操作

  • DisposableBean:定义销毁bean时的操作