【Spring源码开整】03. 手写IOC容器--面向对象拆分

1. 目标

​ 在手写IOC容器–实现功能以面向过程的方式实现了spring IoC容器的基本思路,下面我们以面向对象的思维方式来对该部分的代码进行拆分,进一步模拟spring的IoC实现。

​ 重复强调下自己实现该部分只是为了帮助阅读Spring源码时的理解学习spring的代码结构,不是完整的写一遍Spring,所以仍然只有一些小编理解上的核心逻辑,各位看官也就当个参考就好。

2. Spring IoC中的一些重要接口与类说明

​ 后面的实现会劲量参考着Spring的继承体系来完成以便于在阅读源码时有相应的联想。

2.1 BeanFactory体系中的相关接口和类

相关类和接口UML类图如下
在这里插入图片描述

  1. BeanFactory:

    顶层接口,定义了最为核心的getBean方法,提供容器中是否含有bean、bean是单例还是原型的判断

  2. ListableBeanFactory:

    用来获取某一类Bean、BeanName、BeanDefinition

  3. AutowiredCapableBeanFactory:

    用来处理自动注入的bean工厂

  4. HierarchicalBeanFactory:

    用来处理继承体系的,比如获取 partentBeanFactory

  5. ConfigurableBeanFactory:

    提供一些配置性的接口,完成bean工厂的配置

  6. ConfigurableListBeanFactory:

    提供一些配置性的接口,完成listable bean工厂的配置

  7. AbstractBeanFactory:

    基础的抽象工厂,为ConfigurableBeanFactory SPI提供能力

  8. AbstractAutowireCapableBeanFactory:

    提供Bean创建(具有构造函数解析),属性填充,自动装配和初始化。

  9. DefaultListableBeanFactory:这是一个完整的bean工厂(前面不是接口就是实现类),含有BeanDefinition元数据。通常用它来注册BeanDefinition

  10. XmlBeanFactory:通过xml来读取BeanDefinition的工厂

2.2 BeanDefinitionRegistry和SingletonBeanRegistry的实现类及作用

  1. BeanDefinitionRegistry

    用来保存(hold) BeanDefinition的接口。它是spring中唯一的用来封装BeanDefinition注册的接口

  2. SingletonBeanRegistry

    为共享(shared) bean实例定义注册的接口。ps:这里所谓的共享实现方式就是单例了

3. 手写简单的IoC容器

上一节的话搬过来,不过各个需求点的实现就要改成和Spring对应的类(会有简化):

写之前先来看看需要什么(下面给出的代码很多异常、null的处理都没有给出主要聚焦核心流程)

  1. 为了读取配置类完成解析封装,先搞个流处理把配置文件读进来。
public interface Resource {
    InputStream getResource();
}
public class ClasspathResource implements Resource {
    private String resource;
    public ClasspathResource(String resource) {
        this.resource = resource;
    }
    @Override
    public InputStream getResource() {
        return this.getClass().getClassLoader().getResourceAsStream(resource);
    }
}
  1. 为了记录BeanDefinition要弄个东西存起来

    之前实现我们用的一个Map,这里把Map封装下改成一2.2小节提及的BeanDefinitionRegistry,它是一个接口,我们定义get/set方法(名字换了下模仿spring嘛)

public interface BeanDefinitionRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
    BeanDefinition getBeanDefinition(String beanName);
}
  1. xml解析与BeanDefinition注册

    之前我们分析过xml读取后需要封装成BeanDefinition对象,需要一个类来解析xml,一个类完成注册。

    XmlBeanDefinitionReader控制注册流程,XmlBeanDefinitionDocumentReader控制解析流程

    需要转换输入流为Document对象使用工具类来完成这一职责。

public class XmlBeanDefinitionReader {
    private BeanDefinitionRegistry beanDefinitionRegistry;
    public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry){
        this.beanDefinitionRegistry = beanDefinitionRegistry;
    }
    public void registerBeanDefinitions(InputStream inputStream){
        Document document = DocumentUtils.createDocument(inputStream);
        XmlBeanDefinitionDocumentReader xmlBeanDefinitionDocumentReader = 
            new XmlBeanDefinitionDocumentReader(beanDefinitionRegistry);
        // dom解析与beanDefinition注册
        xmlBeanDefinitionDocumentReader.loadBeanDefinitions(document.getRootElement());
    }
}
public class XmlBeanDefinitionDocumentReader {
  private BeanDefinitionRegistry beanDefinitionRegistry;
  public XmlBeanDefinitionDocumentReader(BeanDefinitionRegistry beanDefinitionRegistry) {
        this.beanDefinitionRegistry = beanDefinitionRegistry;
    }

    public void loadBeanDefinitions(Element rootElement) {
        List<Element> elements = rootElement.elements();
        for (Element element : elements) {
            String name = element.getName();
            if (name.equals("bean")) {//解析bean标签,偷懒就只做了这一个
                parseDefaultElement(element);
            } else {//解析自定标签
                parseCustomElement(element);//没实现,现在也用不到
            }
        }
    }
    
    private void parseDefaultElement(Element beanElement) {
        try {
            if (Objects.isNull( beanElement )){
                return;
            }
            String id = beanElement.attributeValue("id");
            String name = beanElement.attributeValue("name");
            String clazzName = beanElement.attributeValue("class");
            if (Objects.isNull( clazzName ) || "".equals(clazzName)) {
                return;
            }
            Class<?> clazzType = Class.forName(clazzName);
            // 作用域属性,决定bean的创建缓存
            String scope = beanElement.attributeValue("scope");
            scope = scope == null || "".equals(scope) ? scope : "singleton";
            String beanId = id == null ? name : id;
            beanId = beanId == null ? clazzType.getSimpleName() : beanId;
            BeanDefinition beanDefinition = new BeanDefinition(clazzName, beanId);
            beanDefinition.setScope(scope);
            List<Element> propertyElements = beanElement.elements();
            for (Element propertyElement : propertyElements) {
                //解析<property>标签封装为TypedStringValue、RuntimeBeanReference(上一篇有说明)
                parsePropertyElement(beanDefinition, propertyElement);
            }
            //注册BeanDefinition
            beanDefinitionRegistry.registerBeanDefinition(beanId, beanDefinition);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    private void parsePropertyElement(BeanDefinition beanDefinition, Element propertyElement) {
        String name = propertyElement.attributeValue("name");
        String value = propertyElement.attributeValue("value");
        String ref = propertyElement.attributeValue("ref");
        //PropertyValue封装
        PropertyValue pv;
        if (Objects.nonNull(value ) && !"".equals(value)) {
            TypedStringValue typeStringValue = new TypedStringValue(value);
            Class<?> targetType = 
                getTypeByFieldName(beanDefinition.getClazzName(), name);
            typeStringValue.setTargetType(targetType);
            pv = new PropertyValue(name, typeStringValue);
            beanDefinition.addPropertyValue(pv);
        } else if (Objects.nonNull(ref ) && !"".equals(ref)) {
            RuntimeBeanReference reference = new RuntimeBeanReference(ref);
            beanDefinition.addPropertyValue(new PropertyValue(name, reference));
        }
    }
    private Class<?> getTypeByFieldName(String beanClassName, String name) {
        Class<?> type = null;
        try {
            Class<?> clazz = Class.forName(beanClassName);
            Field field = clazz.getDeclaredField(name);
            type = field.getType();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return type;
    }
}
  1. 为了处理BeanDefinition生产的单例bean

    同样改成2.2小节提及的SingletonBeanRegistry,接口先定义好

public interface SingletonBeanRegistry {
    void registerSingleton(String beanName, Object singletonObject);
    Object getSingleton(String beanName);
}

说明下:对SingletonBeanRegistry的实现DefaultSingletonBeanRegistry直接让AbstractBeanFactory继承了,实际Spring中是继承的DefaultSingletonBeanRegistry的子类FactoryBeanRegistrySupport。后面也会有很多类似的简化处理或者也可以说是偷懒处理

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    // 做单例的缓存
    private Map<String, Object> singletonObjects = new HashMap<>();
    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        this.singletonObjects.put(beanName,singletonObject);
    }
    @Override
    public Object getSingleton(String beanName) {
        return this.singletonObjects.get(beanName);
    }
}
  1. getBean()流程是由AbstractBeanFactory来控制,不过它通过模板方法模式将一些实现下沉了。

    逻辑和上一篇getBean基本相同,不过singletonObject是通过继承DefaultSingletonBeanRegistry实现了,createBean()/getBeanDefinition()的实现下沉到子类。

public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
    @Override
    public Object getBean(String name) {
        Object singletonObject = getSingleton(name);
        if (Objects.nonNull(singletonObject)) {
            return singletonObject;
        }
        BeanDefinition beanDefinition = getBeanDefinition(name);
        singletonObject = createBean(beanDefinition);
        if (beanDefinition.isSingleton()) {
            registerSingleton(name, singletonObject);
        }
        return singletonObject;
    }
    protected abstract BeanDefinition getBeanDefinition(String name);
    protected abstract Object createBean(BeanDefinition beanDefinition);
}

creatBean()由AbstractAutowireCapableBeanFactory完成

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    public Object createBean(BeanDefinition beanDefinition){
        Class<?> clazzType = beanDefinition.getClazzType();
        //1.反射创建对象
        Object bean = createInstanceBean(clazzType);
        //2. DI
        populateBean(bean, beanDefinition);
        return bean;
    }

    /**
     * 通过beanDefinition记录的PropertyValue完成DI
     */
    private void populateBean(Object bean, BeanDefinition beanDefinition) {
        List<PropertyValue> propertyValues = beanDefinition.getPropertyValues();
        if (Objects.isNull( propertyValues) || propertyValues.isEmpty()){
            return;
        }
        for (PropertyValue pv : propertyValues){
            String name = pv.getName();
            Object value = pv.getValue();

            Object valueDefined = null;
            if (value instanceof TypedStringValue) {
                TypedStringValue typedStringValue = (TypedStringValue) value;
                String stringValue = typedStringValue.getValue();
                Class<?> targetType = typedStringValue.getTargetType();

                //这里只解析Integer和String两种
                if (targetType == Integer.class) {
                    valueDefined = Integer.parseInt(stringValue);
                } else if (targetType == String.class) {
                    valueDefined = stringValue;
                }
            } else if (value instanceof RuntimeBeanReference) {
                RuntimeBeanReference beanReference = (RuntimeBeanReference) value;
                String ref = beanReference.getRef();
                valueDefined = getBean(ref);
            }
            setProperty(bean, name, valueDefined);
        }
    }

    /**
     * 反射设置属性
     */
    private void setProperty(Object bean, String name, Object valueToUse) {
        try {
            Class<?> clazz = bean.getClass();
            Field field = clazz.getDeclaredField(name);
            field.setAccessible(true);

            field.set(bean, valueToUse);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //只对无参构造进行实现,spring实际要复杂的多
    private Object createInstanceBean(Class<?> clazzType) {
        try {
            Constructor<?> constructor = clazzType.getDeclaredConstructor();
            return constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }
}

registerBeanDefinition()由DefaultListableBeanFactory完成,注意这个类在spring中有非常重要的地位,这里的实现有点简单

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
    private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitions.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return beanDefinitions.get(beanName);
    }

}

最后试测一把

@Test
public void testGetUserById(){
    // 配置信息加载
    Resource resource = new ClasspathResource("beans.xml");
    InputStream inputStream = resource.getResource();
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader xmlBeanDefinitionReader = 
        new XmlBeanDefinitionReader(beanFactory);
    xmlBeanDefinitionReader.registerBeanDefinitions(inputStream);

    IUserService userService = (IUserService) beanFactory.getBean("userService");
    User userById = userService.getUserById(1);
    System.out.println(userById);
}
User{id=1, username='wxy', birthday=2020-01-01, sex='male', address='中国'}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值