Small Spring系列一:BeanFactory(一)

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

https://user-gold-cdn.xitu.io/2019/1/14/1684b3f12a6bb06f?w=4896&h=3264&f=jpeg&s=1620164
https://user-gold-cdn.xitu.io/2019/1/14/1684b3f12a6bb06f?w=4896&h=3264&f=jpeg&s=1620164

前言

Spring是一個開放源代碼的設計層面框架,它解決的是業務邏輯層和其餘各層的鬆耦合問題,所以它將面向接口的編程思想貫穿整個系統應用。java

準備

  • bean-v1.xml配置bean的信息
  • BeanDefinition用於存放bean的定義
  • BeanFactory獲取bean的信息,實例化bean`
  • BeanFactoryTest測試BeanFactory是否可用

bean-v1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id = "nioCoder" class = "com.niocoder.service.v1.NioCoderService">
    </bean>

    <bean id ="invalidBean" class="xxx.xxx">
    </bean>
</beans>
複製代碼

BeanDefinition

bean-v1.xml中定義了每一個bean,但這些信息咱們該如何存儲呢? spring是經過BeanDefinition接口來描述bean的定義git

BeanDefinition

package com.niocoder.beans;

/** * bean.xml bean的定義 * @author zhenglongfei */
public interface BeanDefinition {

    /** * 獲取bean.xml中 bean的全名 如 "com.niocoder.service.v1.NioCoderService" * @return */
    String getBeanClassName();
}

複製代碼

GenericBeanDefinition

GenericBeanDefinition實現了BeanDefinition接口github

package com.niocoder.beans.factory.support;


import com.niocoder.beans.BeanDefinition;

/** * BeanDefinition 實現類 * * @author zhenglongfei */
public class GenericBeanDefinition implements BeanDefinition {

    private String id;
    private String beanClassName;

    public GenericBeanDefinition(String id, String beanClassName) {
        this.id = id;
        this.beanClassName = beanClassName;
    }

    public String getBeanClassName() {
        return this.beanClassName;
    }
}


複製代碼

BeanFactory

咱們已經使用BeanDefinition來描述bean-v1.xmlbean的定義,下面咱們使用BeanFactory來獲取bean的實例spring

BeanFactory

package com.niocoder.beans.factory;

import com.niocoder.beans.BeanDefinition;

/** * 建立bean的實例 * @author zhenglongfei */
public interface BeanFactory {

    /** * 獲取bean的定義 * @param beanId * @return */
    BeanDefinition getBeanDefinition(String beanId);

    /** * 獲取bean的實例 * @param beanId * @return */
    Object getBean(String beanId);
}

複製代碼

DefaultBeanFactory

DefaultBeanFactory實現了BeanFactory接口編程

package com.niocoder.beans.factory.support;

import com.niocoder.beans.BeanDefinition;
import com.niocoder.beans.factory.BeanCreationException;
import com.niocoder.beans.factory.BeanDefinitionStoreException;
import com.niocoder.beans.factory.BeanFactory;
import com.niocoder.util.ClassUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/** * BeanFactory的默認實現類 * * @author zhenglongfei */
public class DefaultBeanFactory implements BeanFactory {

    private static final String ID_ATTRIBUTE = "id";

    private static final String CLASS_ATTRIBUTE = "class";
    /** * 存放BeanDefinition */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /** * 根據文件名稱加載,解析bean.xml * * @param configFile */
    public DefaultBeanFactory(String configFile) {
        loadBeanDefinition(configFile);
    }

    /** * 具體解析bean.xml的方法 使用dom4j * * @param configFile */
    private void loadBeanDefinition(String configFile) {
        ClassLoader cl = ClassUtils.getDefaultClassLoader();
        try (InputStream is = cl.getResourceAsStream(configFile)) {
            SAXReader reader = new SAXReader();
            Document doc = reader.read(is);

            Element root = doc.getRootElement();
            Iterator<Element> elementIterator = root.elementIterator();
            while (elementIterator.hasNext()) {
                Element ele = elementIterator.next();
                String id = ele.attributeValue(ID_ATTRIBUTE);
                String beanClassName = ele.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition bd = new GenericBeanDefinition(id, beanClassName);
                this.beanDefinitionMap.put(id, bd);
            }
        } catch (Exception e) {
            throw new BeanDefinitionStoreException("IOException parsing XML document", e);
        }
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanId) {
        return this.beanDefinitionMap.get(beanId);
    }

    @Override
    public Object getBean(String beanId) {
        BeanDefinition bd = this.getBeanDefinition(beanId);
        if (bd == null) {
            throw new BeanCreationException("BeanDefinition does not exist");
        }
        ClassLoader cl = ClassUtils.getDefaultClassLoader();

        String beanClassName = bd.getBeanClassName();
        try {
            // 使用反射建立bean的實例,須要對象存在默認的無參構造方法
            Class<?> clz = cl.loadClass(beanClassName);
            return clz.newInstance();
        } catch (Exception e) {
            throw new BeanCreationException("Bean Definition does not exist");
        }
    }
}

複製代碼

BeanFactoryTest

以上,咱們已經建立了bean.xmlBeanDefinition來描述bean的定義,而且使用BeanFactory來獲取bean的實例。下面咱們來測試一下BeanFactory是否可用。框架

package com.niocoder.test.v1;

import com.niocoder.beans.BeanDefinition;
import com.niocoder.beans.factory.BeanCreationException;
import com.niocoder.beans.factory.BeanDefinitionStoreException;
import com.niocoder.beans.factory.BeanFactory;
import com.niocoder.beans.factory.support.DefaultBeanFactory;
import com.niocoder.service.v1.NioCoderService;
import org.junit.Assert;
import org.junit.Test;

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

/** * BeanFactory 測試類 */
public class BeanFactoryTest {

    /** * 測試獲取bean */
    @Test
    public void testGetBean() {
        BeanFactory factory = new DefaultBeanFactory("bean-v1.xml");
        BeanDefinition bd = factory.getBeanDefinition("nioCoder");

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

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

        assertNotNull(nioCoderService);
    }

    /** * 測試無效的bean */
    @Test
    public void testInvalidBean() {
        BeanFactory factory = new DefaultBeanFactory("bean-v1.xml");
        try {
            factory.getBean("invalidBean");
        } catch (BeanCreationException e) {
            return;
        }

        Assert.fail("expect BeanCreationException ");
    }

    /** * 測試無效的xml */
    @Test
    public void testInvalidXML() {
        try {
            new DefaultBeanFactory("xxx.xml");
        } catch (BeanDefinitionStoreException e) {
            return;
        }

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

複製代碼

代碼下載

類圖

https://user-gold-cdn.xitu.io/2019/1/14/1684b3f12a7c3f3e?w=1625&h=977&f=png&s=72286
https://user-gold-cdn.xitu.io/2019/1/14/1684b3f12a7c3f3e?w=1625&h=977&f=png&s=72286
相關文章
相關標籤/搜索