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