查看原文
其他

Small Spring系列一:BeanFactory(一)

人生如逆旅,我亦是行人。

前言

Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。

准备

  • bean-v1.xml配置 bean的信息

  • BeanDefinition用于存放 bean的定义

  • BeanFactory获取bean 的信息,实例化bean`

  • BeanFactoryTest测试 BeanFactory是否可用

bean-v1.xml

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans>

  3.    <bean id = "nioCoder"

  4.        class = "com.niocoder.service.v1.NioCoderService">

  5.    </bean>


  6.    <bean id ="invalidBean"

  7.        class="xxx.xxx">

  8.    </bean>

  9. </beans>

BeanDefinition

bean-v1.xml中定义了每个 bean,但这些信息我们该如何存储呢? spring是通过 BeanDefinition接口来描述 bean的定义

BeanDefinition

  1. package com.niocoder.beans;


  2. /**

  3. * bean.xml bean的定义

  4. * @author zhenglongfei

  5. */

  6. public interface BeanDefinition {


  7.    /**

  8.     * 获取bean.xml中 bean的全名 如 "com.niocoder.service.v1.NioCoderService"

  9.     * @return

  10.     */

  11.    String getBeanClassName();

  12. }

GenericBeanDefinition

GenericBeanDefinition实现了 BeanDefinition接口

  1. package com.niocoder.beans.factory.support;



  2. import com.niocoder.beans.BeanDefinition;


  3. /**

  4. * BeanDefinition 实现类

  5. *

  6. * @author zhenglongfei

  7. */

  8. public class GenericBeanDefinition implements BeanDefinition {


  9.    private String id;

  10.    private String beanClassName;


  11.    public GenericBeanDefinition(String id, String beanClassName) {

  12.        this.id = id;

  13.        this.beanClassName = beanClassName;

  14.    }


  15.    public String getBeanClassName() {

  16.        return this.beanClassName;

  17.    }

  18. }

BeanFactory

我们已经使用 BeanDefinition来描述 bean-v1.xmlbean的定义,下面我们使用 BeanFactory来获取 bean的实例

BeanFactory

  1. package com.niocoder.beans.factory;


  2. import com.niocoder.beans.BeanDefinition;


  3. /**

  4. * 创建bean的实例

  5. * @author zhenglongfei

  6. */

  7. public interface BeanFactory {


  8.    /**

  9.     * 获取bean的定义

  10.     * @param beanId

  11.     * @return

  12.     */

  13.    BeanDefinition getBeanDefinition(String beanId);


  14.    /**

  15.     * 获取bean的实例

  16.     * @param beanId

  17.     * @return

  18.     */

  19.    Object getBean(String beanId);

  20. }

DefaultBeanFactory

DefaultBeanFactory实现了 BeanFactory接口

  1. package com.niocoder.beans.factory.support;


  2. import com.niocoder.beans.BeanDefinition;

  3. import com.niocoder.beans.factory.BeanCreationException;

  4. import com.niocoder.beans.factory.BeanDefinitionStoreException;

  5. import com.niocoder.beans.factory.BeanFactory;

  6. import com.niocoder.util.ClassUtils;

  7. import org.dom4j.Document;

  8. import org.dom4j.Element;

  9. import org.dom4j.io.SAXReader;


  10. import java.io.InputStream;

  11. import java.util.Iterator;

  12. import java.util.Map;

  13. import java.util.concurrent.ConcurrentHashMap;



  14. /**

  15. * BeanFactory的默认实现类

  16. *

  17. * @author zhenglongfei

  18. */

  19. public class DefaultBeanFactory implements BeanFactory {


  20.    private static final String ID_ATTRIBUTE = "id";


  21.    private static final String CLASS_ATTRIBUTE = "class";

  22.    /**

  23.     * 存放BeanDefinition

  24.     */

  25.    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();


  26.    /**

  27.     * 根据文件名称加载,解析bean.xml

  28.     *

  29.     * @param configFile

  30.     */

  31.    public DefaultBeanFactory(String configFile) {

  32.        loadBeanDefinition(configFile);

  33.    }


  34.    /**

  35.     * 具体解析bean.xml的方法 使用dom4j

  36.     *

  37.     * @param configFile

  38.     */

  39.    private void loadBeanDefinition(String configFile) {

  40.        ClassLoader cl = ClassUtils.getDefaultClassLoader();

  41.        try (InputStream is = cl.getResourceAsStream(configFile)) {

  42.            SAXReader reader = new SAXReader();

  43.            Document doc = reader.read(is);


  44.            Element root = doc.getRootElement();

  45.            Iterator<Element> elementIterator = root.elementIterator();

  46.            while (elementIterator.hasNext()) {

  47.                Element ele = elementIterator.next();

  48.                String id = ele.attributeValue(ID_ATTRIBUTE);

  49.                String beanClassName = ele.attributeValue(CLASS_ATTRIBUTE);

  50.                BeanDefinition bd = new GenericBeanDefinition(id, beanClassName);

  51.                this.beanDefinitionMap.put(id, bd);

  52.            }

  53.        } catch (Exception e) {

  54.            throw new BeanDefinitionStoreException("IOException parsing XML document", e);

  55.        }

  56.    }


  57.    @Override

  58.    public BeanDefinition getBeanDefinition(String beanId) {

  59.        return this.beanDefinitionMap.get(beanId);

  60.    }


  61.    @Override

  62.    public Object getBean(String beanId) {

  63.        BeanDefinition bd = this.getBeanDefinition(beanId);

  64.        if (bd == null) {

  65.            throw new BeanCreationException("BeanDefinition does not exist");

  66.        }

  67.        ClassLoader cl = ClassUtils.getDefaultClassLoader();


  68.        String beanClassName = bd.getBeanClassName();

  69.        try {

  70.            // 使用反射创建bean的实例,需要对象存在默认的无参构造方法

  71.            Class<?> clz = cl.loadClass(beanClassName);

  72.            return clz.newInstance();

  73.        } catch (Exception e) {

  74.            throw new BeanCreationException("Bean Definition does not exist");

  75.        }

  76.    }

  77. }

BeanFactoryTest

以上,我们已经创建了 bean.xmlBeanDefinition来描述 bean的定义,并且使用 BeanFactory来获取 bean的实例。下面我们来测试一下 BeanFactory是否可用。

  1. package com.niocoder.test.v1;


  2. import com.niocoder.beans.BeanDefinition;

  3. import com.niocoder.beans.factory.BeanCreationException;

  4. import com.niocoder.beans.factory.BeanDefinitionStoreException;

  5. import com.niocoder.beans.factory.BeanFactory;

  6. import com.niocoder.beans.factory.support.DefaultBeanFactory;

  7. import com.niocoder.service.v1.NioCoderService;

  8. import org.junit.Assert;

  9. import org.junit.Test;


  10. import static org.junit.Assert.assertEquals;

  11. import static org.junit.Assert.assertNotNull;


  12. /**

  13. * BeanFactory 测试类

  14. */

  15. public class BeanFactoryTest {


  16.    /**

  17.     * 测试获取bean

  18.     */

  19.    @Test

  20.    public void testGetBean() {

  21.        BeanFactory factory = new DefaultBeanFactory("bean-v1.xml");

  22.        BeanDefinition bd = factory.getBeanDefinition("nioCoder");


  23.        assertEquals("com.niocoder.service.v1.NioCoderService", bd.getBeanClassName());


  24.        NioCoderService nioCoderService = (NioCoderService) factory.getBean("nioCoder");


  25.        assertNotNull(nioCoderService);

  26.    }


  27.    /**

  28.     * 测试无效的bean

  29.     */

  30.    @Test

  31.    public void testInvalidBean() {

  32.        BeanFactory factory = new DefaultBeanFactory("bean-v1.xml");

  33.        try {

  34.            factory.getBean("invalidBean");

  35.        } catch (BeanCreationException e) {

  36.            return;

  37.        }


  38.        Assert.fail("expect BeanCreationException ");

  39.    }


  40.    /**

  41.     * 测试无效的xml

  42.     */

  43.    @Test

  44.    public void testInvalidXML() {

  45.        try {

  46.            new DefaultBeanFactory("xxx.xml");

  47.        } catch (BeanDefinitionStoreException e) {

  48.            return;

  49.        }


  50.        Assert.fail("expect BeanDefinitionStoreException ");

  51.    }

  52. }

代码下载

  • github:https://github.com/longfeizheng/small-spring/tree/20190914_BeanFactory_v1

类图

推荐: SpringBoot WebFlux 入门案例

上一篇:测试微服务:工具和框架


 关注公众号

点击原文阅读更多


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存