1. 概述
控制反转(Inverse Of Control)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序。
控制:在java中指的是对象的控制权限(创建、销毁)
反转:指的是对象控制权由原来 由开发者在类中手动控制 反转到 由Spring容器控制
举例说明:
- 传统方式
之前我们需要一个userDao实例,需要开发者自己手动创建 new UserDao();
- IOC方式
现在我们需要一个userDao实例,直接从spring的IOC容器获得,对象的创建权交给了spring控制
2. 自定义IOC容器
2.1 介绍
需求
实现service层与dao层代码解耦合
步骤分析
- 创建java项目,导入自定义IOC相关坐标
- 编写Dao接口和实现类
- 编写Service接口和实现类
- 编写测试代码
2.2 实现
1)创建java项目,导入自定义IOC相关坐标
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2)编写Dao接口和实现类
package com.lagou.dao;
public interface IUserDao {
public void save();
}
package com.lagou.dao.impl;
import com.lagou.dao.IUserDao;
public class UserDaoImpl implements IUserDao {
public void save() {
System.out.println("dao被调用了,保存成功...");
}
}
3)编写Service接口和实现类
package com.lagou.service;
public interface IUserService {
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
package com.lagou.service.impl;
import com.lagou.dao.IUserDao;
import com.lagou.service.IUserService;
import com.lagou.utils.BeanFactory;
public class UserServiceImpl implements IUserService {
public void save() {
// 调用dao层方法 传统方式 :存在编译期依赖:耦合重
IUserDao userDao = new UserDaoImpl();
userDao.save();
}
}
4)编写测试代码
package com.lagou.test;
import com.lagou.service.IUserService;
import com.lagou.service.impl.UserServiceImpl;
import org.junit.Test;
public class SpringTest {
@Test
public void test1() {
// 获取业务层对象
IUserService userService = new UserServiceImpl();
// 调用save方法
userService.save();
}
}
5)问题
当前service对象和dao对象耦合度太高,而且每次new的都是一个新的对象,导致服务器压力过大。
解耦合的原则是编译期不依赖,而运行期依赖就行了。
6)编写beans.xml
把所有需要创建对象的信息定义在配置文件中。
<beans>
<!--id:标识 class:存的就是要生成实例的类的全路径-->
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
</beans>
7)编写BeanFactory工具类
package com.lagou.utils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BeanFactory {
private static Map<String,Object> iocmap = new HashMap<>();
// 程序启动时,初始化对象实例
static {
//1.读取配置文件
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
//2.解析xml(dom4j)
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(resourceAsStream);
//3.编写xpath表达式
String xpath = "//bean";
//4.获取到所有的bean标签
List<Element> list = document.selectNodes(xpath);
//5.遍历并使用反射创建对象实例,存到map集合(ioc容器)中
for (Element element : list) {
String id = element.attributeValue("id");
//className : com.lagou.dao.impl.UserDaoImpl
String className = element.attributeValue("class");
//使用反射生成实例对象
Object o = Class.forName(className).newInstance();
// 存到map中 key:id value:o
iocmap.put(id,o);
}
} catch (DocumentException | ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static Object getBean(String beanId){
Object o = iocmap.get(beanId);
return o;
}
}
8)修改UserServiceImpl实现类
package com.lagou.service.impl;
import com.lagou.dao.IUserDao;
import com.lagou.service.IUserService;
import com.lagou.utils.BeanFactory;
public class UserServiceImpl implements IUserService {
public void save() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 调用dao层方法 传统方式 :存在编译期依赖:耦合重
//IUserDao userDao = new UserDaoImpl();
//反射
// IUserDao userDao = (IUserDao) Class.forName("com.lagou.dao.impl.UserDaoImpl").newInstance();
IUserDao userDao = (IUserDao) BeanFactory.getBean("userDao");
userDao.save();
}
}
3. 知识小结
- 其实升级后的BeanFactory就是一个简单的Spring的IOC容器所具备的功能。
- 之前我们需要一个userDao实例,需要开发者自己手动创建 new UserDao();
- 现在我们需要一个userdao实例,直接从spring的IOC容器获得,对象的创建权交给了spring控制
- 最终目标:代码解耦合
节选自拉钩教育JAVA系列教程