Spring之IOC仿实现

Spring之IOC仿实现,第1张

Spring之IOC仿实现

文章目录
  • 前言
  • 一、框架实现原理图解
  • 二、仿Spring实现简易IOC机制
    • 1、设计 *** 作Bean的相关数据结构
      • 1、 *** 作bean的基础数据结构BeanDefinition
      • 2、bean的引用类(Ref)
      • 3、Bean属性值类
      • 4、Bean属性值实体集合类
    • 2、设计实现资源加载器接口
      • 1、定义一个资源输入接口
      • 2、实现资源接口
      • 3、实现一个资源加载器
    • 3、设计实现XML文件解析器
      • 1、设计BeanDefinition读取接口
      • 2、设计定义一个BeanDefinition读取的抽象类
    • 4、设计实现Bean的自动生成工厂
      • 1、定义一个beanFactory
      • 2、定义一个beanFactory的抽象类
      • 3、实现BeanFactory具体创建功能
    • 5、编写测试
      • 1、定义一个HelloWorld实体
      • 2、定义一个引用HelloWorld实体的实体
      • 3、resource文件夹下编写XML文件
      • 4、编写测试类
  • 总结


前言

在Spring框架中,IOC控制反转机制是其中的核心概念,为深入理解Spring中IOC的原理、实现机制,学习仿SpringIOC搭建简易版本。


一、框架实现原理图解

二、仿Spring实现简易IOC机制 1、设计 *** 作Bean的相关数据结构 1、 *** 作bean的基础数据结构BeanDefinition
package com.huangjunli.beandefinition;


public class BeanDefinition {

    
    private Object bean;

    
    private Class beanClass;

    
    private String ClassName;

    
    private PropertyValues propertyValues = new PropertyValues();

    
    public Object getBean() {
        return this.bean;
    }

    
    public void setBean(Object bean) {
        this.bean = bean;
    }

    
    public Class getBeanclass() {
        return this.beanClass;
    }

    
    public void setClassname(String name) {
        this.ClassName = name;
        try {
            this.beanClass = Class.forName(name);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    
    public PropertyValues getPropertyValues() {
        return this.propertyValues;
    }

    
    public void setPropertyValues(PropertyValues pv) {
        this.propertyValues = pv;
    }

}
2、bean的引用类(Ref)
package com.huangjunli.beandefinition;


public class BeanReference {

  
  private String name;
  
  private Object bean;

  
  public BeanReference(String name) {
    this.name = name;
  }

  
  public void setName(String name) {
    this.name = name;
  }

  
  public String getName() {
    return this.name;
  }

  
  public void setBean(Object bean) {
    this.bean = bean;
  }

  
  public Object getBean() {
    return this.bean;
  }
}
3、Bean属性值类
package com.huangjunli.beandefinition;


public class PropertyValue {

  
  private final String name;

  
  private final Object value;

  
  public PropertyValue(String name, Object value) {
    this.name = name;
    this.value = value;
  }

  
  public String getname() {
    return this.name;
  }

  
  public Object getvalue() {
    return this.value;
  }
}
4、Bean属性值实体集合类
package com.huangjunli.beandefinition;

import java.util.ArrayList;
import java.util.List;


public class PropertyValues {

  
  private final List propertyValueList = new ArrayList<>();

  
  public PropertyValues() {
  }

  
  public void addPropertyValue(PropertyValue pv) {
    propertyValueList.add(pv);
  }

  
  public List getPropertyValues() {
    return propertyValueList;
  }
}
2、设计实现资源加载器接口

1、定义一个资源输入接口

通过该接口获取到指定资源的输入流对象。

package com.huangjunli.io;

import java.io.InputStream;


public interface Resource {

    
    InputStream getInputstream() throws Exception;

}
2、实现资源接口
package com.huangjunli.io;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;


public class ResourceUrl implements Resource {

    
    private final URL url;

    
    public ResourceUrl(URL url) {
        this.url = url;
    }

    
    @Override
    public InputStream getInputstream() throws Exception {
        URLConnection urlConnection = url.openConnection();
        urlConnection.connect();
        return urlConnection.getInputStream();

    }

}
3、实现一个资源加载器

通过资源加载器获取资源,提供给XML文件读取使用。

package com.huangjunli.io;

import java.net.URL;


public class ResourceLoader {

  
  public ResourceUrl getResource(String location) {
    URL url = this.getClass().getClassLoader().getResource(location);
    return new ResourceUrl(url);
  }
}
3、设计实现XML文件解析器

1、设计BeanDefinition读取接口
package com.huangjunli.xml;


public interface BeanDefinitionReader {

}
2、设计定义一个BeanDefinition读取的抽象类

该类定义两个重要属性:其一为注册bean的容器;其二为资源获取的接口对象。

package com.huangjunli.xml;

import com.huangjunli.beandefinition.BeanDefinition;
import com.huangjunli.io.ResourceLoader;

import java.util.HashMap;
import java.util.Map;


public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {

    
    private Map registry;

    
    private ResourceLoader resourceLoader;

    
    protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
        this.registry = new HashMap<>();
        this.resourceLoader = resourceLoader;
    }

    
    public Map getRegistry() {
        return registry;
    }

    
    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

}

3、实现读取XML配置文件的具体方法及解析bean到注册容器中

package com.huangjunli.xml;

import com.huangjunli.beandefinition.BeanDefinition;
import com.huangjunli.beandefinition.BeanReference;
import com.huangjunli.beandefinition.PropertyValue;
import com.huangjunli.io.ResourceLoader;
import org.w3c.dom.document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.documentBuilder;
import javax.xml.parsers.documentBuilderFactory;
import java.io.InputStream;


public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    
    public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
        super(resourceLoader);
    }

    public void readerXML(String location) throws Exception {
        // 创建一个资源加载器
        ResourceLoader resourceloader = new ResourceLoader();
        // 从资源加载器中获取输入流
        InputStream inputstream = resourceloader.getResource(location).getInputstream();
        // 获取文档建造者工厂实例
        documentBuilderFactory factory = documentBuilderFactory.newInstance();
        // 工厂创建文档建造者
        documentBuilder docBuilder = factory.newdocumentBuilder();
        // 文档建造者解析流 返回文档对象
        document doc = docBuilder.parse(inputstream);
        // 根据给定的文档对象进行解析,并注册到bean容器中
        registerBeanDefinitions(doc);
        // 关闭流
        inputstream.close();
    }

    
    private void registerBeanDefinitions(document doc) {
        // 读取文档的根元素
        Element root = doc.getdocumentElement();
        // 解析元素的根节点及根节点下的所有子节点并添加进注册容器
        parseBeanDefinitions(root);
    }

    
    private void parseBeanDefinitions(Element root) {
        // 读取根元素的所有子元素
        NodeList nl = root.getChildNodes();
        // 遍历子元素
        for (int i = 0; i < nl.getLength(); i++) {
            // 获取根元素的给定位置的节点
            Node node = nl.item(i);
            // 类型判断
            if (node instanceof Element) {
                // 强转为父类型元素
                Element ele = (Element) node;
                // 解析给给定的节点,包括name,class,property, name, value,ref
                processBeanDefinition(ele);
            }
        }
    }

    
    private void processBeanDefinition(Element ele) {
        // 获取给定元素的 name 属性
        String name = ele.getAttribute("name");
        // 获取给定元素的 class 属性
        String className = ele.getAttribute("class");
        // 创建一个bean定义对象
        BeanDefinition beanDefinition = new BeanDefinition();
        // 设置bean 定义对象的 全限定类名
        beanDefinition.setClassname(className);
        // 向 bean 注入配置文件中的成员变量
        addPropertyValues(ele, beanDefinition);
        // 向注册容器 添加bean名称和bean定义
        getRegistry().put(name, beanDefinition);
    }

    
    private void addPropertyValues(Element ele, BeanDefinition beandefinition) {
        // 获取给定元素的 property 属性集合
        NodeList propertyNode = ele.getElementsByTagName("property");
        // 循环集合
        for (int i = 0; i < propertyNode.getLength(); i++) {
            // 获取集合中某个给定位置的节点
            Node node = propertyNode.item(i);
            // 类型判断
            if (node instanceof Element) {
                // 将节点向下强转为子元素
                Element propertyEle = (Element) node;
                // 元素对象获取 name 属性
                String name = propertyEle.getAttribute("name");
                // 元素对象获取 value 属性值
                String value = propertyEle.getAttribute("value");
                // 判断value不为空
                if (value != null && value.length() > 0) {
                    // 向给定的 “bean定义” 实例中添加该成员变量
                    beandefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                } else {
                    // 如果为空,则获取属性ref
                    String ref = propertyEle.getAttribute("ref");
                    if (ref == null || ref.length() == 0) {
                        // 如果属性ref为空,则抛出异常
                        throw new IllegalArgumentException(
                                "Configuration problem:  element for property '"
                                        + name + "' must specify a ref or value");
                    }
                    // 如果不为空,测创建一个 “bean的引用” 实例,构造参数为名称,实例暂时为空
                    BeanReference beanRef = new BeanReference(name);
                    // 向给定的 “bean定义” 中添加成员变量
                    beandefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanRef));
                }
            }
        }
    }

}
4、设计实现Bean的自动生成工厂

1、定义一个beanFactory

该接口提供两个功能:其一获取bean;其二注册bean。
package com.huangjunli.factory;

import com.huangjunli.beandefinition.BeanDefinition;

public interface BeanFactory {

    
    Object getBean(String name) throws Exception;

    
    void registerBeanDefinition(String name, BeanDefinition bean) throws Exception;

}
2、定义一个beanFactory的抽象类

该类定义一个创建bean实例的抽象方法。

package com.huangjunli.factory;

import com.huangjunli.beandefinition.BeanDefinition;

import java.util.HashMap;


public abstract class AbstractBeanFactory implements BeanFactory {

    
    private HashMap map = new HashMap<>();

    
    @Override
    public Object getBean(String name) throws Exception {
        BeanDefinition beandefinition = map.get(name);
        if (beandefinition == null) {
            throw new IllegalArgumentException("No bean named " + name + " is defined");
        }
        Object bean = beandefinition.getBean();
        if (bean == null) {
            bean = doCreate(beandefinition);
        }
        return bean;
    }

    
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beandefinition) throws Exception {
        Object bean = doCreate(beandefinition);
        beandefinition.setBean(bean);
        map.put(name, beandefinition);
    }

    
    abstract Object doCreate(BeanDefinition beandefinition) throws Exception;
}
3、实现BeanFactory具体创建功能
package com.huangjunli.factory;

import com.huangjunli.beandefinition.BeanDefinition;
import com.huangjunli.beandefinition.BeanReference;
import com.huangjunli.beandefinition.PropertyValue;

import java.lang.reflect.Field;


public class AutowireBeanFactory extends AbstractBeanFactory {


    
    @Override
    protected Object doCreate(BeanDefinition beandefinition) throws Exception {
        Object bean = beandefinition.getBeanclass().newInstance();
        addPropertyValue(bean, beandefinition);
        return bean;
    }

    
    protected void addPropertyValue(Object bean, BeanDefinition beandefinition) throws Exception {
        // 循环给定 bean 的属性集合
        for (PropertyValue pv : beandefinition.getPropertyValues().getPropertyValues()) {
            // 根据给定属性名称获取 给定的bean中的属性对象
            Field declaredField = bean.getClass().getDeclaredField(pv.getname());
            // 设置属性的访问权限
            declaredField.setAccessible(true);
            // 获取定义的属性中的对象
            Object value = pv.getvalue();
            // 判断这个对象是否是 BeanReference 对象
            if (value instanceof BeanReference) {
                // 将属性对象转为 BeanReference 对象
                BeanReference beanReference = (BeanReference) value;
                // 调用父类的 AbstractBeanFactory 的 getBean 方法,根据bean引用的名称获取实例,此处即是递归
                value = getBean(beanReference.getName());
            }
            // 反射注入bean的属性
            declaredField.set(bean, value);
        }

    }
}
5、编写测试 1、定义一个HelloWorld实体
package com.huangjunli.test;

public class HelloWorld {

  private String text;

  void say() {
    System.out.println(text);
  }

  public String getText() {
    return text;
  }

  public void setText(String text) {
    this.text = text;
  }
}
2、定义一个引用HelloWorld实体的实体
package com.huangjunli.test;

public class ReferenceBean {

  private HelloWorld hello;

  public void say() {
    hello.say();
  }

  public void setHello(HelloWorld hello) {
    this.hello = hello;
  }
}
3、resource文件夹下编写XML文件



    
        
    
    
        
    



文件名随意,与读取时传入的参数匹配即可。

 xml.readerXML("myspring.xml");
4、编写测试类
package com.huangjunli.test;

import com.huangjunli.beandefinition.BeanDefinition;
import com.huangjunli.factory.AutowireBeanFactory;
import com.huangjunli.factory.BeanFactory;
import com.huangjunli.io.ResourceLoader;
import com.huangjunli.xml.XmlBeanDefinitionReader;
import org.junit.Test;

import java.util.Map;

public class XmlBeanDefinitionReaderTest {

    @Test
    public void test() throws Exception {
        // 创建一个XML解析器,携带一个资源加载器
        XmlBeanDefinitionReader xml = new XmlBeanDefinitionReader(new ResourceLoader());
        // 解析该文件
        xml.readerXML("myspring.xml");

        // 创建一个自动注入bean工厂
        BeanFactory beanfactory = new AutowireBeanFactory();
        // 循环xml中的所有bean
        for (Map.Entry beanDefinitionEntry : xml.getRegistry().entrySet()) {
            // 将XML容器中的bean注册到bean工厂
            beanfactory
                    .registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }
        // 获取持有另一个bean对象的bean(也是从容器中取得的)
        ReferenceBean hello = (ReferenceBean) beanfactory.getBean("referenceBean");

        // 调用对象方法
        hello.say();


    }
}
总结

springIOC的原理并不复杂,简单回顾一下实现步骤:

  1. 通过XML文件读取bean信息
  2. 解析加载bean信息到注册容器中
  3. bean工厂底层通过反射完成bean实例的创建

当然spring中的实现需要考虑其他如性能、安全等各方面的因素,因而实现复杂很多。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5677008.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存