- 前言
- 一、框架实现原理图解
- 二、仿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 List2、设计实现资源加载器接口 1、定义一个资源输入接口propertyValueList = new ArrayList<>(); public PropertyValues() { } public void addPropertyValue(PropertyValue pv) { propertyValueList.add(pv); } public List getPropertyValues() { return propertyValueList; } }
通过该接口获取到指定资源的输入流对象。
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 Mapregistry; 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:4、设计实现Bean的自动生成工厂 1、定义一个beanFactoryelement for property '" + name + "' must specify a ref or value"); } // 如果不为空,测创建一个 “bean的引用” 实例,构造参数为名称,实例暂时为空 BeanReference beanRef = new BeanReference(name); // 向给定的 “bean定义” 中添加成员变量 beandefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanRef)); } } } } }
该接口提供两个功能:其一获取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 HashMap3、实现BeanFactory具体创建功能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; }
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的原理并不复杂,简单回顾一下实现步骤:
- 通过XML文件读取bean信息
- 解析加载bean信息到注册容器中
- bean工厂底层通过反射完成bean实例的创建
当然spring中的实现需要考虑其他如性能、安全等各方面的因素,因而实现复杂很多。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)