IoC的定义
IoC控制反转(baiInversion of Control,英文缩写为IoC),把创建对象的权利交给框架,是框架的重要特征,IoC不是一种技术,而是一种设计思想,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。
传统的创建对象方式是通过关键字new进行创建,IoC的思想是通过Spring容器来创建对象,由容器来控制对象。
何为正转,何为反转?传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象,当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了。为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
IoC能做什么?
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出低耦合、高优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IoC和DI
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖于谁:当然是应用程序依赖于IoC容器;
- 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
- 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
依赖注入的几种方式
这里举几个SpringBoot应用IoC思想的几个例子,Springboot会自动加载resources文件下面的application.yml或者application.properties配置文件,因为yml格式可以替代xml格式,功能properties更强大,所以一般都使用yml格式进行书写。
1.对于yml中定义了的bean,可以使用 @value("${对象}") 进行注入。 如果是对象变量,可以直接在变量上使用value注解进行注入。如果是下图这样的静态变量,就需要在set方法上使用value注解。注意:必须是在Spring容器中的对象才能够进行注入,即需要加@Component注解。
student:
name: 小明
age: 15
@Component
public class Student {
public static String name;
public static int age;
@Value("${student.name}")
public void setName(String name){
Student.name = name;
}
@Value("${student.age}")
public void setAge(int age){
Student.age = age;
}
}
2.也可以在需要使用Spring容器值的类上加
@Component和@ConfigurationProperties(prefix=“对象名”),将application.yml中配置的对象student(IOC容器中的值)注入进来。(必须是IoC容器中的对象,才能够被注入值,即必须被声明为@Component注解)。
student:
name: 小明
age: 15
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
public static String name;
public static int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
}
3.可以使用@Configuration、@PropertySource(value=“classpath:test.properties”)、@ConfigurationProperties(prefix=“student”)这三个注解将resources文件下test.properties描述的student对象的属性注入到student对象中(即使用自定义的配置文件,将属性注入到对象中)。 @Configuration注解可以替换为@Component注解,@Configuration注解其实继承了@Component注解,用来表示该类是配置类。
student.name = '小白'
student.age = 16
@Configuration
@PropertySource(value="classpath:application.properties")
@ConfigurationProperties(prefix="student")
public class Student {
public static String name;
public static int age;
public void setName(String name){
Student.name = name;
}
public void setAge(int age){
Student.age = age;
}
}
4.还可以使用@Autowired注解对已经存在于IoC容器中的对象实现自动注入。
IoC的优缺点
优点:
可以灵活提供不同的子类实现(其实就是解耦),提高程序的灵活性、可扩展性和可维护性。由IOC容器通过配置文件来管理对象的生命周期、依赖关系等,这样就不用重新修改并编译具体的代码,从而实现组件之间的解耦。
缺点:
1、创建对象的步骤变复杂了,不直观,当然这是对不习惯这种方式的人来说的。
2、因为使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是微不足道的。
本文参考:
http://jinnianshilongnian.iteye.com/blog/1413846
https://blog.csdn.net/tanglihai/article/details/81353411