IoC全称Inversion of Control,直译为控制反转.
首先是一个常见的场景,比如我们一共有三个类: BookService, UserService, HistoryService
这三个类都需要执行以下操作
- 初始化数据库连接
- 查询数据
- 返回数据
这就带来了问题,
- 实例化一个类的时候会带来冗余的代码,比如初始化数据库连接 。
- 组件里面依赖的资源需要进行销毁? 但是这个组件可能又被其他组件依赖,这样依赖很容易出现资源无法销毁的情况
- 一个组件里面,实例化太多的组件,依赖关系复杂,不好测试,容易出错
解决方法:
把这些组件的创建,交给系统管理,而不是在类里面实例化组件,而是统一由系统创建,最后由系统销毁
如何做?
- Spring里面的 IOC 负责创建组件
- IOC 负责根据依赖关系组装组件
- IOC 负责销毁和关闭资源
一般有2种方法,一个是通过 set* 方法注入,一个是通过构造函数注入. 这里都做一下记录
set 和 构造函数注入
首先设置三个类: UserService / EmailService / LogService
UserService
package com.example.code.services;public class UserService {private EmailService emailService;private LogService logService;// 构造函数注入public UserService(LogService logService){this.logService = logService;}// 通过 set* 方法注入public void setEmailService(EmailService emailService) {this.emailService = emailService;}public User Register(){System.out.println("Register User");emailService.SendEmail(); // send email...System.out.println("register successful");this.logService.record("UserService"); // log information for user servicereturn new User();}}
新建 Main.java 启动函数
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserService userService = context.getBean(UserService.class);
User user = userService.Register();
}
}
管理注入的XML为
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="logService" class="com.example.code.services.LogService" />
<bean id="userService" class="com.example.code.services.UserService">
<!-- set 函数注入 -->
<property name="emailService" ref="emailService" />
<!-- 构造函数注入 -->
<constructor-arg name="logService" ref="logService" />
</bean>
<bean id="emailService" class="com.example.code.services.EmailService">
<constructor-arg name="logService" ref="logService" />
</bean>
</beans>
工厂函数静态注入
最后还有一种工厂函数注入
我们新建一个类 CheckService.java
/*
* @Description:
* @Date: 2020/10/13
*/
package com.example.code.service;
public class CheckService {
public void check(){
System.out.println("checking...");
}
}
然后创建 工厂方法, CheckServiceFactory.java
public class CheckServiceFactory {
public static final CheckService createCheckService(){
return new CheckService();
}
}
然后注入到 UserService 中
public class UserService {
private CheckService checkService;
public void setCheckService(CheckService checkService) {
this.checkService = checkService;
}
public String register(){
checkService.check();
emailService.sendEmail();
return "register successful";
}
}
跟 set 方法注入没什么不同,但是 xml 的配置是不同的
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="checkService" class="com.example.code.service.CheckServiceFactory" factory-method="createCheckService"/>
<bean id="userService" class="com.example.code.service.UserService">
<property name="checkService" ref="checkService" />
</bean>
</beans>
这里指向了 工厂类,还指明了工厂函数。 spring 在读取配置的时候,到这个地方,就不会去调用类的反射,而是交由工厂函数去处理实例化组件。
工厂函数实例注入
最后一种是实例工厂的方法注入
新建 LogService.java
/*
* @Description:
* @Date: 2020/10/13
*/
package com.example.code.service;
public class LogService {
public void record(String name){
System.out.println("recode log: " + name);
}
}
然后常见工厂方法
/*
* @Description:
* @Date: 2020/10/13
*/
package com.example.code.service;
public class LogServiceFactory {
public LogService createLogService(){
return new LogService();
}
}
然后是UserService.java
public class UserService {
private LogService logService;
public void setLogService(LogService logService) {
this.logService = logService;
}
public String register(){
logService.record("user");
return "register successful";
}
}
最后看一下 xml
<bean id="logService" factory-bean="logServiceFactory" factory-method="createLogService" />
<bean id="logServiceFactory" class="com.example.code.service.LogServiceFactory" />
<bean id="userService" class="com.example.code.service.UserService">
<property name="logService" ref="logService" />
</bean>
