浅谈Spring IOC

Spring的核心是IOC和AOP,今天只谈IOC,这部分内容主要集中在spring-beans包下。

容器的实现

IOC(Inversion of Control)即控制反转,也叫做依赖注入(DI),主要是实现一个容器,而该容器的功能就是进行装配、生产的工厂。同时,Spring的一个核心概念就是将所有配置信息当做bean来处理。

从而得到一个叫做BeanFactory的接口类。

package com.ddt.summer.bean.factory;

/**
 * 
 * @author [email protected]
 */
public interface BeanFactory {
	
	/**
	 * 放入bean对象
	 * @param name
	 * @param object
	 */
	void putBean(String name, Object object);
	
	/**
	 * 根据bean名称获取bean实例
	 * @param name
	 * @return
	 */
	Object getBean(String name);

	/**
	 * 是否含有名称为name的bean
	 * @param name
	 * @return
	 */
	boolean containsBean(String name);

}

这个容器需要能进行配置的bean的读取,所以需要有一个集合类来存储这些bean,下面列出一个beanFactory的实现类

package com.ddt.summer.bean.factory;

import java.util.ArrayList;
import java.util.List;

import com.ddt.summer.bean.entity.Bean;

public class XmlBeanFactory implements BeanFactory {
	
	private List<Bean> beans = new ArrayList<Bean>();
	
	private static XmlBeanFactory factory;
	
	private XmlBeanFactory(){
	}
	
	public static XmlBeanFactory getInstance(){
		if(factory==null){
			factory = new XmlBeanFactory();
		}
		return factory;
	}
	
	@Override
	public void putBean(String name, Object object){
		Bean bean = new Bean();
		bean.setId(name);
		bean.setObject(object);
		beans.add(bean);
	}

	@Override
	public Object getBean(String name) {
		for(Bean bean:beans){
			if(bean.getId().equals(name)){
				return bean.getObject();
			}
		}
		return null;
	}

	@Override
	public boolean containsBean(String name) {
		for(Bean bean:beans){
			if(bean.getId().equals(name)){
				return true;
			}
		}
		return false;
	}
}

注意到上面的XmlBeanFactory使用了单例模式,是为了保证我们每次获取到的容器是同一个容器。

配置信息注入

有了容器后,我们就需要将配置好的信息,通过反射注入到我们实现好了的容器中。

下面举一个简单的例子,我们实现几个类。

首先实现一个大的接口类

package test;

public interface Animal {
	
	void say();

}

再来一个老鼠类

package test;

public class Mouse implements Animal{
	
	private String name;
	
	public void setName(String name){
		this.name=name;
	}
	
	public String getName(){
		return this.name;
	}
	@Override
	public void say(){
		System.out.println("mouse is "+name);
	}

}

有了老鼠,就自然会有猫类:

package test;

public class Cat implements Animal {
	
	private String name;
	private Mouse mouse;

	@Override
	public void say() {
		System.out.println("i am "+name+" !");
		System.out.println("catched:");
			mouse.say();
	}
	
	public String getName(){
		return this.name;
	}
	
	public Mouse getMouse(){
		return mouse;
	}
	
	public void setName(String name){
		this.name = name;
	}
	
	public void setMouse(Mouse mouse){
		this.mouse = mouse;
	}

}

有了这几个类,我们就可以开始我们的配置了,配置如下

<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="animal2" class="test.Mouse">
	<property name="name" value="jerry" />
</bean>
<bean id="animal" class="test.Cat">
	<property name="name" value="tom" />
	<property name="mouse" ref="animal2" />
</bean>
</beans>

最后,我们剩下的工作就是将这些配置信息注入到工厂容器里了

package simple;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import com.ddt.summer.bean.factory.BeanFactory;
import com.ddt.summer.bean.factory.XmlBeanFactory;

public class XmlReader {
	
	public static void read(){
		URL base = ClassLoader.getSystemResource("");
		File file = new File(base.getFile(),"applicationContext.xml");
		SAXBuilder builder = new SAXBuilder();
		try {
			Document doc = builder.build(file);
			Element beans = doc.getRootElement();
			paking(beans);
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private static void paking(Element beans){
		List<Element> list = beans.getChildren();
		for(Element beanEle:list){
			String id = beanEle.getAttributeValue("id");
			String className = beanEle.getAttributeValue("class");
			try {
				Class<?> clazz = Class.forName(className);
				Object obj = clazz.newInstance();
				BeanFactory factory = XmlBeanFactory.getInstance();
				factory.putBean(id, obj);
				List<Element> properties = beanEle.getChildren();
				for(Element property:properties){
					if("property".equals(property.getName())){
						String name = property.getAttributeValue("name");
						String value = property.getAttributeValue("value");
						if(value!=null){
							Field field = clazz.getDeclaredField(name);
							PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
							Method setterMethod = pd.getWriteMethod();
							setterMethod.invoke(obj,value);
						}
					}
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (IntrospectionException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static Object getBean(String id){
		read();
		BeanFactory factory = XmlBeanFactory.getInstance();
		return factory.getBean(id);
	}

}

这里我用Jdom来实现了对xml的读取。这样就愉快的将这些配置好的信息注入到了我们的工厂容器里了。

再来一个简单的测试

public static void main(String[] args){
		Animal a1 = (Animal) XmlReader.getBean("animal");
		a1.say();
	}

输出结果如下:

i am tom !
catched:
mouse is jerry

显然,我的如下代码基本实现了IOC的功能,由XmlBeanFactory和XmlReader来实现对具体bean的组装、生成和管理。

具体代码可以在github上找到,https://github.com/daidetian/summer

你可能感兴趣的:(浅谈Spring IOC)