Spring的两大核心思想是IOC和AOP,而Spring Boot在Spring的基础上进行了自动配置。本章我们就一起来剖析这些特性的内在原理。
你真的懂IOC吗
IOC(Inversion of Control,控制反转)并不是一种技术,而是一种编程思想,最常见的实现方式叫作“依赖注入”(Dependency Injection,简称DI),还有一种方式叫作“依赖查找”(Dependency Lookup,简称DL)。
实现方式
IOC的实现方式主要有两种:一种是依赖查找,另一种是依赖注入。两者的主要区别在于查找是主动行为,而注入是被动行为。依赖查找会主动寻找对象所需的依赖,同时获取依赖对象的时机也是可以自行控制的;依赖注入则会被动地等待容器为其注入依赖对象,由容器通过类型或者名称将被依赖对象注入相应的对象中。
依赖查找
依赖查找会主动获取,在需要的时候通过调用框架提供的方法来获取对象,并且在获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态。EJB就是使用依赖查找实现的控制反转。依赖查找建立在Java EE的JNDI规范之上,但随着EJB的衰落,其实现方式也慢慢无人问津。
依赖注入
依赖注入是控制反转最常见的实现方式,这在很大程度上得益于Spring在Java领域的垄断地位。在Spring中使用依赖注入可以通过如下4种方式:
· 基于接口
· 基于Set方法
· 基于构造函数
· 基于注解
由于注解方便、好用,目前几乎所有系统都使用注解的方式来完成依赖注入。实际上,我们已经对使用注解的依赖注入方式很熟悉了,在之前的小节中就已经用过N次了。首先使用@Controller、@Service、@Component等注解将类声明为Spring Bean,然后使用@Autowire注解注入依赖对象。
传统方式vs控制翻转
241我们都知道,Class A代表A是一个类,而A a=new A()代表创建一个A类型的对象a。在没有控制反转的情况下,在A类中使用B类的b对象时,需要在A类中新建一个b对象。如果我们使用控制反转,则只需要先在A类中声明一个私有的b对象,即private B b,然后将创建b对象的工作交由容器来完成。容器会根据注解或者配置文件将b对象注入A类的实例中。
虽然上面介绍了很多,但是要想真真切切地感受一下控制反转思想相对于传统方式有哪些不同,还需要通过实实在在的代码示例才可以。前情提要:有个小伙儿叫小明,他有一个爱好——喜欢出去逛。下面我们用代码来实现一下。
传统方式
首先创建一个Person类,它有一个hangOut方法,一个Driveable接口,然后创建一个Bike类并实现Driveable接口:
共享单车
刚刚大学毕业的小明虽然很喜欢出去玩,但是只能骑一个共享单车。
虽然小明只能在周围5千米范围内逛一逛,不过倒也悠哉。
开车自驾
经过不断地学习和努力,小明收入越来越高,终于有了一辆属于自己的车,以后出去逛就可以开车了
这时小明可以开车来一场“说走就走”的自驾游啦,快哉!
诗和远方
后来,小明不再满足自驾游的短途旅行,喜欢上了“诗和远方”,于是其出游的交通工具变成了高铁
这时小明只要买一张火车票就可以游历祖国的大好河山,美哉!
异国风光
没过多久,小明游遍了国内的美景,开始向往异国风光,于是开启了飞行之旅。
这时小明可以乘坐飞机去感受异域文化,体味不同的风土人情,妙哉!
漂洋过海
你可能猜到了,没过多久,小明的心又飘向了海洋。
这时小明可以乘风破浪,感受无边的海洋,壮哉!
虽然出去玩可以悠哉、快哉、美哉、妙哉甚至壮哉,但是我们发现,每换一种交通工具,就需要修改Person类,非常麻烦,而且不符合面向对象的开闭原则。接下来我们看看使用控制反转会发生什么。
控制反转
改造Person类,将交通工具从hangOut方法中提取出来,变成Person类的私有成员变量:
由上面代码可以看出,小明可以在出行前选择乘坐哪种交通工具,无须再修改Person类。小明只需要关心“要不要出去逛”即可,不需要关心到底怎么去。而采用传统方式根本无法做到这一点。