我们将分为几步来编写简易 IOC,首先设计组件,再设计接口,然后关注实现。
1. 设计组件。
我们还记得Spring中最重要的有哪些组件吗?BeanFactory 容器,BeanDefinition Bean的基本数据结构,当然还需要加载Bean的资源加载器。大概最后最重要的就是这几个组件。
容器用来存放初始化好的Bean,BeanDefinition 就是Bean的基本数据结构,比如Bean的名称,Bean的属性 PropertyValue,Bean的方法,是否延迟加载,依赖关系等。资源加载器就简单了,就是一个读取
2. 设计接口
首先肯定需要一个BeanFactory,就是Bean容器,容器接口至少有2个最简单的方法,一个是获取Bean,一个注册Bean.
/** * 需要一个beanFactory 定义ioc 容器的一些行为 比如根据名称获取bean, 比如注册bean,参数为bean的名称,bean的定义 * * @author stateis0 * @version 1.0.0 * @Date 2017/11/30 */public interface BeanFactory { /** * 根据bean的名称从容器中获取bean对象 * * @param name bean 名称 * @return bean实例 * @throws Exception 异常 */ Object getBean(String name) throws Exception; /** * 将bean注册到容器中 * * @param name bean 名称 * @param bean bean实例 * @throws Exception 异常 */ void registerBeanDefinition(String name, BeanDefinition bean) throws Exception;}根据Bean的名字获取Bean对象,注册参数有2个,一个是Bean的名字,一个是 BeanDefinition 对象。
定义完了Bean最基本的容器,还需要一个最简单 BeanDefinition 接口,我们为了方便,但因为我们这个不必考虑扩展,因此可以直接设计为类,BeanDefinition 需要哪些元素和方法呢?
需要一个 Bean 对象,一个Class对象,一个ClassName字符串,还需要一个元素集合 PropertyValues。这些就能组成一个最基本的 BeanDefinition 类了。那么需要哪些方法呢?其实就是这些属性的get set 方法。
我们看看该类的详细:
package cn.thinkinjava.myspring;/*** bean 的定义** @author stateis0*/public class BeanDefinition { /** * bean */ private Object bean; /** * bean 的 CLass 对象 */ private Class beanClass; /** * bean 的类全限定名称 */ private String ClassName; /** * 类的属性集合 */ private PropertyValues propertyValues = new PropertyValues(); /** * 获取bean对象 */ public Object getBean() { return this.bean; } /** * 设置bean的对象 */ public void setBean(Object bean) { this.bean = bean; } /** * 获取bean的Class对象 */ public Class getBeanclass() { return this.beanClass; } /** * 通过设置类名称反射生成Class对象 */ public void setClassname(String name) { this.ClassName = name; try { this.beanClass = Class.forName(name); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取bean的属性集合 */ public PropertyValues getPropertyValues() { return this.propertyValues; } /** * 设置bean的属性 */ public void setPropertyValues(PropertyValues pv) { this.propertyValues = pv; }}有了基本的 BeanDefinition 数据结构,还需要一个从
package cn.thinkinjava.myspring;import cn.thinkinjava.myspring.io.ResourceLoader;import java.util.HashMap;import java.util.Map;/** * 抽象的bean定义读取类 * * @author stateis0 */public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader { /** * 注册bean容器 */ private Map<String, BeanDefinition> registry; /** * 资源加载器 */ private ResourceLoader resourceLoader; /** * 构造器器必须有一个资源加载器, 默认插件创建一个map容器 * * @param resourceLoader 资源加载器 */ protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) { this.registry = new HashMap<>(); this.resourceLoader = resourceLoader; } /** * 获取容器 */ public Map<String, BeanDefinition> getRegistry() { return registry; } /** * 获取资源加载器 */ public ResourceLoader getResourceLoader() { return resourceLoader; } }有了这几个抽象类和接口,我们基本能形成一个雏形,BeanDefinitionReader 用于从
3. 如何实现
刚刚我们说了具体的流程:从
2. 初始化我们需要的Bean(不是Bean定义)并且实现依赖注入
我们知道Bean定义是不能干活的,只是一些Bean的信息,就好比一个人,BeanDefinition 就相当你在公安局的档案,但是你人不在公安局,可只要公安局拿着你的档案就能找到你。就是这样一个关系。
那我们就根据BeanFactory的设计来设计一个抽象类 AbstractBeanFactory。
package cn.thinkinjava.myspring.factory;import cn.thinkinjava.myspring.BeanDefinition;import java.util.HashMap;/** * 一个抽象类, 实现了 bean 的方法,包含一个map,用于存储bean 的名字和bean的定义 * * @author stateis0 */public abstract class AbstractBeanFactory implements BeanFactory { /** * 容器 */ private HashMap<String, BeanDefinition> map = new HashMap<>(); /** * 根据bean的名称获取bean, 如果没有,则抛出异常 如果有, 则从bean定义对象获取bean实例 */ @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; } /** * 注册 bean定义 的抽象方法实现,这是一个模板方法, 调用子类方法doCreate, */ @Override public void registerBeanDefinition(String name, BeanDefinition beandefinition) throws Exception { Object bean = doCreate(beandefinition); beandefinition.setBean(bean); map.put(name, beandefinition); } /** * 减少一个bean */ abstract Object doCreate(BeanDefinition beandefinition) throws Exception;}package cn.thinkinjava.myspring.factory;import cn.thinkinjava.myspring.BeanDefinition;import cn.thinkinjava.myspring.PropertyValue;import cn.thinkinjava.myspring.BeanReference;import java.lang.reflect.Field;/** * 实现自动注入和递归注入(spring 的标准实现类 DefaultListableBeanFactory 有 1810 行) * * @author stateis0 */public class AutowireBeanFactory extends AbstractBeanFactory { /** * 根据bean 定义创建实例, 并将实例作为key, bean定义作为value存放,并调用 addPropertyValue 方法 为给定的bean的属性进行注入 */ @Override protected Object doCreate(BeanDefinition beandefinition) throws Exception { Object bean = beandefinition.getBeanclass().newInstance(); addPropertyValue(bean, beandefinition); return bean; } /** * 给定一个bean定义和一个bean实例,为给定的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); } }}可以看到 doCreate 方法使用了反射创建了一个对象,并且还需要对该对象进行属性注入,如果属性是 ref 类型,那么既是依赖关系,则需要调用 getBean 方法递归的去寻找那个Bean(因为最后一个Bean 的属性肯定是基本类型)。这样就完成了一次获取实例化Bean操作,并且也实现类依赖注入。
4. 总结
我们通过这些代码实现了一个简单的 IOC 依赖注入的功能,也更加了解了 IOC, 以后遇到Spring初始化的问题再也不会手足无措了。直接看源码就能解决。哈哈
good luck !!!
作者:莫那一鲁道
链接:https://www.jianshu.com/p/6e25dc62e3a1
近期热文推荐:
1.Java 15 正式发布, 14 个新特性,刷新你的认知!!
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!
3.我用 Java 8 写了一段逻辑,同事直呼看不懂,你试试看。。
4.吊打 Tomcat ,Undertow 性能很炸!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
原文转载:http://www.shaoqun.com/a/489554.html
杨帆:https://www.ikjzd.com/w/1648
美菜网:https://www.ikjzd.com/w/1874
敦煌网:https://www.ikjzd.com/w/189
我们将分为几步来编写简易IOC,首先设计组件,再设计接口,然后关注实现。1.设计组件。我们还记得Spring中最重要的有哪些组件吗?BeanFactory容器,BeanDefinitionBean的基本数据结构,当然还需要加载Bean的资源加载器。大概最后最重要的就是这几个组件。容器用来存放初始化好的Bean,BeanDefinition就是Bean的基本数据结构,比如Bean的名称,Bean的属
reverb:https://www.ikjzd.com/w/1273
空中云汇:https://www.ikjzd.com/w/2684
PPC遭恶意点击?教你4招预防和应对恶意点击!:https://www.ikjzd.com/home/504
shopee店铺优惠券设置与马来站最新店铺装饰!:https://www.ikjzd.com/home/100206
斐济岛特产购物指南 - :http://tour.shaoqun.com/a/12255.html
没有评论:
发表评论