Spring-IOC的演变

目录
显示
本文从不去大篇幅解释什么是 IOC ,而是谈谈为什么会出现 IOC ,它的出现解决了哪些问题。我觉得从它的演变史可以管中窥豹的理解下。
版本一: 在需要对象的时候直接new对象
这是最原始的做法,这样做的缺点是:
- 耦合度非常高,有编译器的依赖
- 如果该对象发送了变化,使用它的地方也要修改,牵一发而动全身,程序难以维护
版本二: 使用反射创建对象
UserServlet类:
private UserService userService = (UserService) BeanFactory.getBean("com.zuoyueer.service.UserServiceImp");
------------------------------------------------------
class BeanFactory{
public static Object getBean(String className) {
try {
return Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
使用反射,对版本一进行了改进:
优点:
- 不存在编译器依赖了,即使删除了需要创建的对象的类,也不会影响使用它的类
缺点:
- 存在硬编码问题, 如果对象的类改变了名字, getBean传入的类的全限定名字符串也要改变
版本三: 使用反射+配置文件的方式
UserServlet类:
private static UserService userService = (UserService) BeanFactory.getBean("userService");
------------------------------------------
class BeanFactory{
public static Object getBean(String key) {
//加载并读取配置文件
//通过参数key得到配置文件中的类的全限定类名
//反射创建对象
return Class.forName(className).newInstance();
}
}
----------------------------------------------
配置文件: beans.xml
<bean id="userService" class="com.zuoyueeer.service.impl.UserServiceImpl"/>
使用反射+配置文件的方式 ,,,对版本二进行优化
优点;
- 没有编译器依赖
- 没有硬编码问题
缺点:
- 有性能问题
- 每次使用都要加载配置文件
- 每次使用都要重新创建对象
版本四: 使用反射+配置文件+静态代码块+容器(集合)的方式
package com.zuoyueeer.util;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Zuoyueer
* Date: 2019/11/19
* Time: 9:44
* @projectName JavaEE
* @description: 进行解耦, 反射创建实现类
*/
public class BeanFactory {
//私有化构造函数,保证单例
private BeanFactory() {
}
//定义容器map,里面存储的是配置文件中对应的全部对象
private static Map<String, Object> map = new HashMap<>();
static {
//只需要在配置文件中解析一次配置文件
InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
//获取Document对象
Document document = saxReader.read(is);
//获得根节点
Element rootElement = document.getRootElement();
//获取全部的子节点
List<Element> elements = rootElement.elements();
//遍历节点,获取每个节点的属性值
for (Element element : elements) {
//获取id属性值,作为map容器的key
String key = element.attributeValue("id");
//获取class属性值
String className = element.attributeValue("class");
//根据class属性值,反射创建对象
Class<?> aClass = Class.forName(className);
Object value = aClass.newInstance();
//把创建的对象作为容器的value
map.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
public static Object getBean(String id) {
return map.get(id);
}
使用反射+配置文件+静态代码块+容器(集合)的方式
优点:
- 没有编译器依赖
- 没有硬编码问题
- 没有性能问题
- 只加载一次配置文件,每个类只创建一个对象
中心思想是: IOC 控制反转 , 我们需要什么对象,容器就给你什么对象,不需要我们new,我们只需要被动的接受对象就行了。
Spring的 IOC 就是使用的第4版本的方式创建对象.