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版本的方式创建对象.

SystemCaller
SystemCaller

https://gravatar.com/noisily745e35dad0

文章: 47

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注