手撕一個spirng IoC的過程

七印miss發表於2019-01-24

概述

IoC(Inversion of Controller),即控制反轉。它是一種設計思想,簡單說就是建立Java物件的過程從之前new出來,變成了由Spring工廠建立出來(由Spring來負責控制物件的生命週期和物件之間的關係)。控制反轉,轉移的就是建立物件的主動權。
tiny-spring實現了基本的 IoC 容器,支援singleton型別的bean,包括初始化、屬性注入、以及依賴 Bean 注入,可從 XML 中讀取配置。

第一步-最基本的容器

IoC最基本的角色有兩個:容器(BeanFactory)和Bean本身。這裡使用BeanDefinition來封裝了bean物件,這樣可以儲存一些額外的元資訊

BeanDefinition類

定義BeanDefinition類來封裝一個spring bean物件

/**
 * 核心bean的定義,其物件被註冊到BeanFactory中
 */
public class BeanDefinition {
    private Object bean;

    public BeanDefinition(Object bean) {
        this.bean = bean;
    }

    public Object getBean() {
        return bean;
    }

}
複製程式碼

BeanFactory類

定義一個Bean工廠類,即容器,用一個Map實現Bean的註冊和獲取。序號產生器制很簡單,key為bean名稱,value為BeanDefinition類物件。

/**
 * bean的工廠類,用於儲存註冊的bean
 */
public class BeanFactory {
	/**
	 * 存放Factory裡的所有Bean的詳細資訊,可以看做是Bean的登錄檔
	 */
	private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

	public Object getBean(String name) {
		return beanDefinitionMap.get(name).getBean();
	}

	/**
	 * 將新加的BeanDefinition物件加到登錄檔中
	 * @param name	登錄檔Map的key
	 * @param beanDefinition BeanDefinition物件,儲存了Bean的詳細資訊
	 */
	public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
		beanDefinitionMap.put(name, beanDefinition);
	}
}
複製程式碼

測試

用於測試的bean物件,其只擁有一個方法,沒有成員變數

/**
 * 用於測試的bean
 */
public class HelloWorldService {
    public void helloWorld(){
        System.out.println("Hello World!");
    }
}
複製程式碼

bean註冊與獲取實現的測試類

public class BeanFactoryTest {
	@Test
	public void test() {
		// 1.初始化beanfactory
		BeanFactory beanFactory = new BeanFactory();

		// 2.注入bean
		BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
		beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

        // 3.獲取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}

------------output------------
Hello world!
複製程式碼

第二步-將bean建立放入工廠

step1中的bean是初始化好之後再作為BeanDefinition的入參。實際使用中,我們希望容器來管理bean的建立。於是我們將bean的初始化放入BeanFactory中。為了保證擴充套件性,我們使用介面提取的方法,將BeanFactory替換成介面,而使用AbstractBeanFactoryAutowireCapableBeanFactory作為其實現。"AutowireCapable"的意思是“可自動裝配的”,為我們後面注入屬性做準備。

BeanDefinition類

BeanDefinition類增加一個Class類成員變數用來記錄當前bean的Class型別,以及記錄bean的類全限定名稱。

public class BeanDefinition {
	/**
	 * bean物件
	 */
	private Object bean;

	/**
	 * 記錄bean物件的Class資訊
	 */
	private Class beanClass;

	/**
	 * 記錄bean物件的ClassName
	 */
	private String beanClassName;
	
	/**
	 * 通過bean物件的className載入該物件,並初始化
	 * @param beanClassName 類名
	 */
	public void setBeanClassName(String beanClassName) {
		this.beanClassName = beanClassName;
		try {
			this.beanClass = Class.forName(beanClassName);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	// 省略其他的getter和setter方法
}
複製程式碼

BeanFactory容器介面

public interface BeanFactory {

    Object getBean(String name);

    void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}
複製程式碼

實現容器的虛擬類

public abstract class AbstractBeanFactory implements BeanFactory {
    /**
     * 實際儲存bean的容器
     */
	private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

	@Override
    public Object getBean(String name) {
		return beanDefinitionMap.get(name).getBean();
	}

	@Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
	}

    /**
     * 初始化bean,實際建立方式交給子類
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition);
}
複製程式碼

可自動裝配的實現類

public class AutowireCapableBeanFactory extends AbstractBeanFactory {
    /**
     * 根據類限定名稱建立類例項
     * @param beanDefinition
     * @return
     */
    @Override
    protected Object doCreateBean(BeanDefinition beanDefinition) {
        try {
            Object bean = beanDefinition.getBeanClass().newInstance();
            return bean;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
複製程式碼

測試

public class BeanFactoryTest {
	@Test
	public void test() {
		// 1.初始化beanfactory
		BeanFactory beanFactory = new AutowireCapableBeanFactory();

		// 2.注入bean
		BeanDefinition beanDefinition = new BeanDefinition();
		String className = new HelloWorldService().getClass().getName();
        beanDefinition.setBeanClassName(className);
		beanFactory.registerBeanDefinition(className, beanDefinition);

        // 3.獲取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean(className);
        helloWorldService.helloWorld();
    }
}

------------------output-----------------
Hello World!
複製程式碼

第三步-為bean注入屬性

這一步,我們想要為bean注入屬性。我們選擇將屬性注入資訊儲存成PropertyValue物件,並且儲存到BeanDefinition中。這樣在初始化bean的時候,我們就可以根據ropertyValue來進行bean屬性的注入。Spring本身使用了setter來進行注入,這裡為了程式碼簡潔,我們使用Field的形式來注入。

PropertyValue類,用於單個屬性注入

public class PropertyValue {
    // 屬性
    private final String name;
    // 屬性值
    private final Object value;

    public PropertyValue(String name, Object value) {
        this.name = name;
        this.value = value;
    }
    // 省略getter和setter方法
}
複製程式碼

PropertyValues類,包裝一個物件所有的PropertyValue

public class PropertyValues {
	private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();

	public PropertyValues() {
	}

	public void addPropertyValue(PropertyValue pv) {
        //TODO:這裡可以對於重複propertyName進行判斷,直接用list沒法做到
		this.propertyValueList.add(pv);
	}

	public List<PropertyValue> getPropertyValues() {
		return this.propertyValueList;
	}
}
複製程式碼

為BeanDefinition新增一個屬性成員

public class BeanDefinition {
	private Object bean;
	private Class beanClass;
	private String beanClassName;
	/**
	 * 儲存bean的屬性
	 */
	 private PropertyValues propertyValues;
	
	// 省略其他的getter和setter方法
}
複製程式碼

AutowireCapableBeanFactory虛擬類

增加對注入屬性的繫結

public class AutowireCapableBeanFactory extends AbstractBeanFactory {

	@Override
	protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
		Object bean = createBeanInstance(beanDefinition);
		applyPropertyValues(bean, beanDefinition);
		return bean;
	}

	protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
		return beanDefinition.getBeanClass().newInstance();
	}

    // 使用反射繫結屬性列表
	protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
		for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
			Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
			declaredField.setAccessible(true);
			declaredField.set(bean, propertyValue.getValue());
		}
	}
}
複製程式碼

測試

用於測試的HelloWorldService不再是隻含有一個方法了,新增了一個String型別的成員變數

public class HelloWorldService {

    private String text;

    public void helloWorld(){
        System.out.println(text);
    }

    public void setText(String text) {
        this.text = text;
    }
}
複製程式碼

相應的測試方法實現了屬性繫結結果的驗證。

public class BeanFactoryTest {
	@Test
	public void test() throws Exception {
		// 1.初始化beanfactory
		BeanFactory beanFactory = new AutowireCapableBeanFactory();

		// 2.bean定義
		BeanDefinition beanDefinition = new BeanDefinition();
		String className = new HelloWorldService().getClass().getName();
		beanDefinition.setBeanClassName(className);

		// 3.設定屬性
		PropertyValues propertyValues = new PropertyValues();
		propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));
        beanDefinition.setPropertyValues(propertyValues);

		// 4.生成bean
		beanFactory.registerBeanDefinition(className, beanDefinition);

		// 5.獲取bean
		HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean(className);
		helloWorldService.helloWorld();
	}
}

-----------output---------
Hello World!
複製程式碼

第四步-讀取xml配置來初始化bean

這麼大一坨初始化程式碼讓人心煩。這裡的BeanDefinition只是一些配置,我們還是用xml來初始化吧。我們定義了BeanDefinitionReader初始化bean,它有一個實現是XmlBeanDefinitionReader。這一步其實就是從xml中讀取數然後再用反射實現bean的轉化,原理和手工裝配並沒有很大的區別。先看看用於測試的xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean name="helloWorldService" class="us.codecraft.tinyioc.HelloWorldService">
        <property name="text" value="Hello World!"></property>
    </bean>
</beans>
複製程式碼

xml檔案中包含一個名為helloWorldService的bean以及其一個text屬性。

BeanDefinitionReader介面

這個記錄用來從配置中讀取BeanDefinition。

public interface BeanDefinitionReader {

    void loadBeanDefinitions(String location) throws Exception;
}
複製程式碼

AbstractBeanDefinitionReader虛類

其實現了BeanDefinitionReader介面,但沒有真正去定義載入bean的實現方式。主要功能是配置一個BeanDefinition的容器,並定義一個載入器。

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {

    private Map<String,BeanDefinition> registry;

    private ResourceLoader resourceLoader;

    protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
        this.registry = new HashMap<String, BeanDefinition>();
        this.resourceLoader = resourceLoader;
    }

    public Map<String, BeanDefinition> getRegistry() {
        return registry;
    }

    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }
}
複製程式碼

XmlBeanDefinitionReader類

XmlBeanDefinitionReader類繼承AbstractBeanDefinitionReader,實現了從xml檔案中解析並繫結spring bean及其屬性。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
		super(resourceLoader);
	}

	@Override
	public void loadBeanDefinitions(String location) throws Exception {
		InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
		doLoadBeanDefinitions(inputStream);
	}

	protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = factory.newDocumentBuilder();
		Document doc = docBuilder.parse(inputStream);
		// 解析bean
		registerBeanDefinitions(doc);
		inputStream.close();
	}

	public void registerBeanDefinitions(Document doc) {
		Element root = doc.getDocumentElement();

		parseBeanDefinitions(root);
	}

	protected 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;
				processBeanDefinition(ele);
			}
		}
	}

	// 解析
	protected void processBeanDefinition(Element ele) {
		String name = ele.getAttribute("name");
		String className = ele.getAttribute("class");
        BeanDefinition beanDefinition = new BeanDefinition();
        processProperty(ele,beanDefinition);
        // 繫結bean
        beanDefinition.setBeanClassName(className);
		getRegistry().put(name, beanDefinition);
	}

	// 繫結屬性
    private void processProperty(Element ele,BeanDefinition beanDefinition) {
        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;
                String name = propertyEle.getAttribute("name");
                String value = propertyEle.getAttribute("value");
                beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value));
            }
        }
    }
}
複製程式碼

測試

public class BeanFactoryTest {

	@Test
	public void test() throws Exception {
		// 1.讀取配置
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
		xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");

		// 2.初始化BeanFactory並註冊bean
		BeanFactory beanFactory = new AutowireCapableBeanFactory();
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}

		// 3.獲取bean
		HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
		helloWorldService.helloWorld();
	}
}
複製程式碼

第五步-為bean注入bean

使用xml配置之後,似乎裡我們熟知的Spring更近了一步!但是現在有一個大問題沒有解決:我們無法處理bean之間的依賴,無法將bean注入到bean中,所以它無法稱之為完整的IoC容器!如何實現呢?我們定義一個BeanReference,來表示這個屬性是對另一個bean的引用。這個在讀取xml的時候初始化,並在初始化bean的時候,進行解析和真實bean的注入。先看下測試用的xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean name="outputService" class="us.codecraft.tinyioc.OutputService">
        <property name="helloWorldService" ref="helloWorldService"></property>
    </bean>

    <bean name="helloWorldService" class="us.codecraft.tinyioc.HelloWorldService">
        <property name="text" value="Hello World!"></property>
        <property name="outputService" ref="outputService"></property>
    </bean>
</beans>
複製程式碼

可以發現相比上一步,bean對了一個引用型別的成員變數。

BeanReference類

該類表示這個屬性是對另一個spring bean的引用。

public class BeanReference {

    private String name;

    private Object bean;

    public BeanReference(String name) {
        this.name = name;
    }
    
    // 省略getter/setter方法
}
複製程式碼

BeanDefinition類

public class BeanDefinition {

	private Object bean;

	private Class beanClass;

	private String beanClassName;

	private PropertyValues propertyValues = new PropertyValues();
	
	// 省略getter/setter方法
複製程式碼

AbstractBeanFactory類

同時為了解決迴圈依賴的問題,我們使用lazy-init的方式,將createBean的事情放到getBean的時候才執行,是不是一下子方便很多?這樣在注入bean的時候,如果該屬性對應的bean找不到,那麼就先建立!因為總是先建立後注入,所以不會存在兩個迴圈依賴的bean建立死鎖的問題。

public abstract class AbstractBeanFactory implements BeanFactory {

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

	private final List<String> beanDefinitionNames = new ArrayList<String>();

    // 實現懶載入
	@Override
	public Object getBean(String name) throws Exception {
		BeanDefinition beanDefinition = beanDefinitionMap.get(name);
		if (beanDefinition == null) {
			throw new IllegalArgumentException("No bean named " + name + " is defined");
		}
		Object bean = beanDefinition.getBean();
		if (bean == null) {
			bean = doCreateBean(beanDefinition);
		}
		return bean;
	}

	@Override
	public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
		beanDefinitionMap.put(name, beanDefinition);
		beanDefinitionNames.add(name);
	}

	public void preInstantiateSingletons() throws Exception {
		for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
			String beanName = (String) it.next();
			getBean(beanName);
		}
	}

	/**
	 * 初始化bean
	 * 
	 * @param beanDefinition
	 * @return
	 */
	protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;

}
複製程式碼

AutowireCapableBeanFactory類

由於引入了bean之間的依賴,所以需要當前spring bean的成員變數不是基本資料型別時,需要新增而外的處理方法。

public class AutowireCapableBeanFactory extends AbstractBeanFactory {

	@Override
	protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
		Object bean = createBeanInstance(beanDefinition);
        beanDefinition.setBean(bean);
		applyPropertyValues(bean, beanDefinition);
		return bean;
	}

	protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
		return beanDefinition.getBeanClass().newInstance();
	}

	protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
		for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
			Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
			declaredField.setAccessible(true);
			Object value = propertyValue.getValue();
			// 處理成員變數是引用型別的情況
			if (value instanceof BeanReference) {
				BeanReference beanReference = (BeanReference) value;
				value = getBean(beanReference.getName());
			}
			declaredField.set(bean, value);
		}
	}
複製程式碼

XmlBeanDefinitionReader類

同樣的,需要單獨處理xml檔案中property元素為引用型別的情況。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    ...
    	private void processProperty(Element ele, BeanDefinition beanDefinition) {
		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;
				String name = propertyEle.getAttribute("name");
				String value = propertyEle.getAttribute("value");
				if (value != null && value.length() > 0) {
					beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
				} else {
				    // 處理引用型別
					String ref = propertyEle.getAttribute("ref");
					if (ref == null || ref.length() == 0) {
						throw new IllegalArgumentException("Configuration problem: <property> element for property '"
								+ name + "' must specify a ref or value");
					}
					BeanReference beanReference = new BeanReference(ref);
					beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
				}
			}
		}
	}
    ...
}
複製程式碼

測試

相應的需要更改測試所用的模型類

public class HelloWorldService {
    private String text;
    // 增加一個類成員變數
    private OutputService outputService;

    public void helloWorld(){
        outputService.output(text);
    }
    
    // 省略setter方法
}

public class OutputService {
    private HelloWorldService helloWorldService;

    public void output(String text){
        Assert.assertNotNull(helloWorldService);
        System.out.println(text);
    }

    public void setHelloWorldService(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }
}
複製程式碼

測試方法:

@Test
	public void testPreInstantiate() throws Exception {
		// 1.讀取配置
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
		xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");

		// 2.初始化BeanFactory並註冊bean
		AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory();
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}

        // 3.初始化bean
        beanFactory.preInstantiateSingletons();

		// 4.獲取bean
		HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
		helloWorldService.helloWorld();
	}
複製程式碼

第六步-ApplicationContext登場

現在BeanFactory的功能齊全了,但是使用起來有點麻煩。於是我們引入熟悉的ApplicationContext介面,並在AbstractApplicationContextrefresh()方法中進行bean的初始化工作。

ApplicationContext介面

ApplicationContext介面繼承BeanFactoryBeanFactory是對內的容器,而ApplicationContext即對外提供的介面。

public interface ApplicationContext extends BeanFactory {
}
複製程式碼

AbstractApplicationContext類

public abstract class AbstractApplicationContext implements ApplicationContext {
    protected AbstractBeanFactory beanFactory;

    public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public void refresh() throws Exception{
    }

    // 實際提供bean的還是BeanFactory
    @Override
    public Object getBean(String name) throws Exception {
        return beanFactory.getBean(name);
    }
}
複製程式碼

ClassPathXmlApplicationContext類

ClassPathXmlApplicationContext類定義refresh方法,實現類的自動載入和初始化工作。

public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

	private String configLocation;

	public ClassPathXmlApplicationContext(String configLocation) throws Exception {
		this(configLocation, new AutowireCapableBeanFactory());
	}

	public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
		super(beanFactory);
		this.configLocation = configLocation;
		refresh();
	}

	@Override
	public void refresh() throws Exception {
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
		xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
		}
	}
}
複製程式碼

測試

public class ApplicationContextTest {
    @Test
    public void test() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
        HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}
複製程式碼

頓時感覺清爽了很多。

參考

tiny-spring 分析
tiny-spring原始碼閱讀筆記

相關文章