springIOC的简单实现

来源:互联网 发布:倪妮井柏然 知乎 编辑:程序博客网 时间:2024/06/08 15:18

主要内容参考 http://www.cnblogs.com/fingerboy/p/5425813.html

Ioc—Inversion of Control,即控制反转,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。即Spring管理对象生命周期及依赖关系



程序中所有的Bean之间的依赖关系我们是放在一个xml文件中进行维护的,就是applicationContext.xml

ConfigManager类完成的功能是读取xml,并将所有读取到有用的信息封装到我们创建的一个Map<String,Bean>集合中,用来在初始化容器时创建bean对象.

定义一个BeanFactory的接口,接口中有一个getBean(String name)方法,用来返回你想要创建的那个对象.

然后定义一个该接口的实现类ClassPathXmlApplicationContext.就是在这个类的构造方法中,初始化容器,通过调用ConfigManager的方法返回的Map集合,通过反射一一创建bean对象.这里需要注意,对象的创建有两个时间点,这取决与bean标签中scope属性的值:

如果scope="singleton",那么对象在容器初始化时就已创建好,用的时候只需要去容器中取即可.

如果scope="prototype",那么容器中不保存这个bean的实例对象,每次开发者需要使用这个对象时再进行创建.


实体类 Student Teacher

package com.entity;public class Teacher {private String name;private Student student;public String getName() {return name;}public void setName(String name) {this.name = name;}public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}public String toString() {return "Teacher [name=" + name + ", student=" + student + "]";}public Teacher(String name, Student student) {super();this.name = name;this.student = student;}public Teacher() {super();}}package com.entity;public class Student {private String name;private Integer age;private String address;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String toString() {return "Student [name=" + name + ", age=" + age + ", address="+ address + "]";}}

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans><!-- <bean id="str" class="com.lang.String"></bean> --><bean id="teacher" class="com.entity.Teacher"  scope="prototype"><property name="name" value="肖肖"></property><property name="student" ref="student"></property></bean><bean id="student" class="com.entity.Student"><property name="name" value="小明"></property><property name="age" value="1"></property><property name="address" value="陕西临潼"></property></bean></beans>

用于封装Bean标签的类Bean

package com.config;import java.util.ArrayList;import java.util.List;public class Bean {private String name;private String className;private String scope="singleton";private List<Property> properties=new ArrayList<Property>();public String getName() {return name;}public void setName(String name) {this.name = name;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public List<Property> getProperties() {return properties;}public void setProperties(List<Property> properties) {this.properties = properties;}}

用于封装Bean子标签Property

package com.config;public class Property {private String name;private String value;private String ref;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public String getRef() {return ref;}public void setRef(String ref) {this.ref = ref;}public String toString() {return "Property [name=" + name + ", value=" + value + ", ref=" + ref+ "]";}}

解析xml文件的ConfigManager

package com.config.parse;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.config.Bean;import com.config.Property;public class ConfigManager {private static Map<String,Bean> map=new HashMap<String,Bean>();public static Map<String,Bean> getConfig(String path){//xml解析器SAXReader reader=new SAXReader();InputStream in=ConfigManager.class.getResourceAsStream(path);Document doc=null;try {doc=reader.read(in);} catch (DocumentException e) {e.printStackTrace();System.out.println("初始化出错");}//从任意节点的位置查找bean节点String xpath="//bean";List<Element> beans=doc.selectNodes(xpath);if(beans!=null){for(Element beanElement:beans){Bean bean=new Bean();String name=beanElement.attributeValue("id");String className=beanElement.attributeValue("class");String scope=beanElement.attributeValue("scope");bean.setName(name);bean.setClassName(className);if(scope!=null){bean.setScope(scope);}List<Element> properties=beanElement.elements("property");if(properties!=null){for(Element propertyElement:properties){Property property=new Property();String pname=propertyElement.attributeValue("name");String pvalue=propertyElement.attributeValue("value");String pref=propertyElement.attributeValue("ref");property.setName(pname);property.setValue(pvalue);property.setRef(pref);bean.getProperties().add(property);}}map.put(name, bean);}}return map;}}

注入属性的工具类 InjectUtil

package com.utils;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class InjectUtil {//注入valuepublic static void injectValue(Object obj,String name,String value){Method[] methods=obj.getClass().getMethods();String methodName="set"+name.substring(0, 1).toUpperCase()+name.substring(1);for(Method method:methods){if(method.getName().equals(methodName)){Class<?>[] parameters=method.getParameterTypes();Class<?> parameter=parameters[0];try {Object paraObj=parameter.getConstructor(String.class).newInstance(value);method.invoke(obj, paraObj);} catch (InstantiationException | IllegalAccessException| IllegalArgumentException| InvocationTargetException | NoSuchMethodException| SecurityException e) {e.printStackTrace();}}}}//注入refpublic static void injectRef(Object obj,String name,Object ref){Method[] methods=obj.getClass().getMethods();String methodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);for(Method method:methods){if(method.getName().equals(methodName)){try {method.invoke(obj, ref);} catch (IllegalAccessException | IllegalArgumentException| InvocationTargetException e) {e.printStackTrace();}}}}}

BeanFacroty接口

package com.main;public interface BeanFactory {public Object getBean(String name);}

ApplicationContext

package com.main;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import com.config.Bean;import com.config.Property;import com.config.parse.ConfigManager;import com.utils.InjectUtil;public class ClassPathXmlApplicationContext implements BeanFactory{//读取配置文件的mapprivate Map<String,Bean> configMap;private Map<String,Object> context=new HashMap<String,Object>();public ClassPathXmlApplicationContext(String path){configMap=ConfigManager.getConfig(path);for(Entry<String,Bean> entry:configMap.entrySet()){String name=entry.getKey();Bean bean=entry.getValue();Object obj=context.get(name);if(obj==null&&bean.getScope().equals("singleton")){obj=createBean(bean);context.put(name, obj);}}}public Object createBean(Bean bean){String className=bean.getClassName();Class<?> c=null;try {c=Class.forName(className);} catch (ClassNotFoundException e) {e.printStackTrace();}Object obj=null;try {obj=c.newInstance();} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();}List<Property> properties=bean.getProperties();if(properties!=null){for(Property property:properties){String name=property.getName();String value=property.getValue();String ref=property.getRef();if(value!=null){InjectUtil.injectValue(obj, name,value);}if(ref!=null){Object propertyObj=context.get(ref);if(context.get(ref)==null){propertyObj=createBean(configMap.get(ref));if(configMap.get(ref).getScope().equals("singleton")){context.put(ref,propertyObj);}}InjectUtil.injectRef(obj,ref,propertyObj);}}}return obj;}public Object getBean(String name){Bean bean=configMap.get(name);if(bean.getScope().equals("singleton")){return context.get(name);}else{return createBean(bean);}}}

测试类

package com.test;import com.entity.Student;import com.entity.Teacher;import com.main.BeanFactory;import com.main.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args){BeanFactory context=new ClassPathXmlApplicationContext("/ApplicationContext.xml");Student student1=(Student)context.getBean("student");Student student2=(Student)context.getBean("student");System.out.println(student1);System.out.println(student1==student2);Teacher teacher1=(Teacher)context.getBean("teacher");Teacher teacher2=(Teacher)context.getBean("teacher");System.out.println(teacher1);System.out.println(teacher1==teacher2);String s = "";}}
测试结果

Student [name=小明, age=1, address=陕西临潼]
true
Teacher [name=肖肖, student=Student [name=小明, age=1, address=陕西临潼]]
false

只有单例模式容器才会持有该对象的引用,若是原型模式只有客户端持有该对象的引用