自己实现spring核心IOC部分

来源:互联网 发布:杭州做公卫软件 编辑:程序博客网 时间:2024/06/05 22:07

bean

package cn.itcast.bean;public class A {public A() {System.out.println("A对象被创建了!");}private int name;public int getName() {return name;}public void setName(int name) {this.name = name;}}

package cn.itcast.bean;public class B {public B() {System.out.println("B对象被创建了!");}private A a;public A getA() {return a;}public void setA(A a) {this.a = a;}}
package cn.itcast.bean;public class C {public C() {System.out.println("C对象被创建了!");}private B b;public B getB() {return b;}public void setB(B b) {this.b = b;}}

config

package cn.itcast.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 getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}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 List<Property> getProperties() {return properties;}public void setProperties(List<Property> properties) {this.properties = properties;}@Overridepublic String toString() {return "Bean [name=" + name + ", className=" + className + ", scope="+ scope + ", properties=" + properties + "]";}}


package cn.itcast.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;}@Overridepublic String toString() {return "Property [name=" + name + ", value=" + value + ", ref=" + ref+ "]";}}

parse

package cn.itcast.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 cn.itcast.config.Bean;import cn.itcast.config.Property;/** * dom4j实现步骤 * 1创建解析器 * 2.加载配置文件==>document对象 * 3.定义xpath表达式,取出所有的Bean元素 * 4.对Bean元素进行遍历 *   将Bean元素的name/class 属性封装到Bean对象中 *   获得bean元素下所有的Property子元素,将属性name/value封装到Property对象中 *   将Property对象封装到Bean对象中 * 5.在将Bean对象封装到Map中(用于返回的map) * 6.返回map * @author lzqiangPC * */public class ConfigManager {// 读取 配置文件 => 并返回读取结果public static Map<String, Bean> getConfig(String path) {// 创建一个用于返回的map对象Map<String, Bean> map = new HashMap<String, Bean>();// dom4j实现// 1 创建解析器SAXReader reader = new SAXReader();// 2 加载配置文件=>document对象InputStream is = ConfigManager.class.getResourceAsStream(path);Document doc = null;try {doc = reader.read(is);} catch (DocumentException e) {e.printStackTrace();throw new RuntimeException("客官!请检查您的xml配置是否正确!");}// 3 定义xpath表达式,取出所有Bean元素String xpath = "//bean";// 4 对Bean元素进行遍历List<Element> list = doc.selectNodes(xpath);if (list != null) {for (Element beanEle : list) {Bean bean = new Bean();// 将bean元素的name/class 属性封装到Bean对象中String name = beanEle.attributeValue("name");String className = beanEle.attributeValue("class");String scope = beanEle.attributeValue("scope");bean.setName(name);bean.setClassName(className);if (scope != null) {bean.setScope(scope);}// 获得Bean元素下的所有Property子元素 ,将属性name/value/ref封装到Property对象中List<Element> children = beanEle.elements("property");if (children != null) {for (Element child : children) {Property prop = new Property();String pName = child.attributeValue("name");String pValue = child.attributeValue("value");String pRef = child.attributeValue("ref");prop.setName(pName);prop.setRef(pRef);prop.setValue(pValue);// 将Property封装到Bean对象bean.getProperties().add(prop);}}// 将Bean对象封装到Map中(用于返回的map)map.put(name, bean);}}// 5 返回Map结果return map;}}

main

package cn.itcast.main;public interface BeanFactory {//根据Bean的name获得 Bean对象的方法Object getBean(String beanName);}

package cn.itcast.main;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import cn.itcast.config.Bean;import cn.itcast.config.Property;import cn.itcast.config.parse.ConfigManager;import cn.itcast.utils.BeanUtils;public class ClassPathXmlApplicationContext implements BeanFactory {// 希望在ClassPathXmlApplicationContext类一创建// 就初始化spring容器(装载Bean实例的)// 配置信息private Map<String, Bean> config;// 使用一个map来做spring的容器=> 放置我们spring所管理的对象private Map<String, Object> context = new HashMap<String, Object>();/** * 1.读取配置文件获得需要初始化的Bean信息 * 2.遍历配置,初始化Bean * 3.将初始化的Bean放入容器中 * @param path */public ClassPathXmlApplicationContext(String path) {// 1 读取配置文件获得需要初始化的Bean信息config = ConfigManager.getConfig(path);// 2 遍历配置 初始化Beanif (config != null) {for (Entry<String, Bean> en : config.entrySet()) {// 获得配置中的Bean信息String beanName = en.getKey();Bean bean = en.getValue();Object existBean = context.get(beanName);// 因为createBean方法中也会向Context中放置Bean// 我们在初始化之前先要判断容器中是否已经存在了这个Bean.再去完成初始化的工作// 并且我们的Bean的scope属性值为singleton,才将Bean放入容器中if (existBean == null && bean.getScope().equals("singleton")) {// 根据bean配置 创建bean对象Object beanObj = createBean(bean);// 3 将初始化好的Bean放入容器中context.put(beanName, beanObj);}}}}// 根据Bean配置创建Bean实例/* * <bean name="A" class="cn.itcast.bean.A" > <!-- * 将A的属性配置,spring会自动将配置的值注入到A中 --> <property name="name" value="tom" * ></property> </bean> * ########################################### * 1.获得要创建的Bean的class * 2.获得Bean的属性,将其注入 */private Object createBean(Bean bean) {// 1 获得要创建的Bean的ClassString className = bean.getClassName();Class clazz = null;try {clazz = Class.forName(className);} catch (ClassNotFoundException e) {e.printStackTrace();throw new RuntimeException("客官!请检查您Bean的Class配置是否正确!" + className);}// 获得class=> 将class对应的对象创建出来Object beanObj = null;try {beanObj = clazz.newInstance();// 调用空参构造} catch (Exception e) {e.printStackTrace();throw new RuntimeException("客官!您的Bean没有空参构造!" + className);}// 2 需要获得Bean的属性,将其注入if (bean.getProperties() != null) {for (Property prop : bean.getProperties()) {// 注入分两种情况// 获得要注入的属性名称String name = prop.getName();String value = prop.getValue();String ref = prop.getRef();// 注入值类型属性方式2:使用BeanUtils工具类完成属性的注入if (value != null) {// 说明有值类型的属性需要注入Map<String, String[]> paramMap = new HashMap<String, String[]>();paramMap.put(name, new String[] { value });// 调用BeanUtils方法将值类型的属性注入(该种注入=>可以自动完成类型转换)try {org.apache.commons.beanutils.BeanUtils.populate(beanObj, paramMap);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("客官!请检查您的" + name + "属性!");}}// 用于注入Bean类型的属性if (prop.getRef() != null) {// 2> 麻烦=> 其他Bean的注入// 根据属性名称获得注入属性对应的Set方法Method setMethod = BeanUtils.getWriteMethod(beanObj, name);// 因为要注入其他bean到当前bean中,我们先从容器中查找当前要注入的Bean是否已经创建,并放入容器中Object existBean = context.get(prop.getRef());if (existBean == null) {// 说明容器中还不存在我们要注入的Bean// 将Bean创建existBean = createBean(config.get(prop.getRef()));// 将创建好的Bean放入容器中if (config.get(prop.getRef()).getScope().equals("singleton")) {context.put(prop.getRef(), existBean);}}// 调用set方法注入即可try {setMethod.invoke(beanObj, existBean);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("客官!您的Bean的属性" + name+ "没有对应的set方法,或方法参数不正确" + className);}}/* * // 根据属性名称获得注入属性对应的Set方法 Method setMethod = * BeanUtils.getWriteMethod(beanObj,name); // 创建一个需要注入到Bean中的属性 * Object param = null; if(prop.getValue()!=null){ //1> 简单=> * value属性注入 //获得要注入的实行值 String value = prop.getValue(); param = * value; } if(prop.getRef()!=null){ //2> 麻烦=> 其他Bean的注入 *  * // 因为要注入其他bean到当前bean中,我们先从容器中查找当前要注入的Bean是否已经创建,并放入容器中 * Object existBean = context.get(prop.getRef()); *  * if(existBean == null ){ //说明容器中还不存在我们要注入的Bean //将Bean创建 * existBean = createBean(config.get(prop.getRef())); * //将创建好的Bean放入容器中 * if(config.get(prop.getRef()).getScope().equals("singleton")){ * context.put(prop.getRef(), existBean); } } *  * param = existBean; } *  *  * // 调用set方法注入即可 try { setMethod.invoke(beanObj, param); } * catch (Exception e) { e.printStackTrace(); throw new * RuntimeException * ("客官!您的Bean的属性"+name+"没有对应的set方法,或方法参数不正确"+className); } */}}return beanObj;}@Override// 根据Bean的名称获得Bean实例public Object getBean(String beanName) {Object bean = context.get(beanName);// 如果bean的scope配置为prototype .那么 context中就不会包含该Bean对象if (bean == null) {// 如果不存在该Bean对象,那么就创建这个Bean对象bean = createBean(config.get(beanName));}return bean;}}

package cn.itcast.main;import cn.itcast.bean.A;import cn.itcast.bean.B;import cn.itcast.bean.C;public class Test {@org.junit.Testpublic void fun1(){BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");A a = (A) bf.getBean("A");/*A a2 = (A) bf.getBean("A");A a3 = (A) bf.getBean("A");*/System.out.println(a.getName());//tom}@org.junit.Testpublic void fun2(){BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");B b = (B) bf.getBean("B");B b2 = (B) bf.getBean("B");B b3 = (B) bf.getBean("B");B b4 = (B) bf.getBean("B");System.out.println(b.getA().getName());//jerry}@org.junit.Testpublic void fun3(){BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");C c = (C) bf.getBean("C");C c2 = (C) bf.getBean("C");C c3 = (C) bf.getBean("C");C c4 = (C) bf.getBean("C");System.out.println(c.getB().getA().getName());//jerry}}

test;

package cn.itcast.test;import java.util.Map;import cn.itcast.config.Bean;import cn.itcast.config.parse.ConfigManager;public class Test {//测试读取配置文件的ConfigManager.java 是否正确@org.junit.Testpublic void fun1(){Map<String, Bean> config = ConfigManager.getConfig("/applicationContext.xml");System.out.println(config);}}

utils

package cn.itcast.utils;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;/** * 反射:就是一套用来描述类的API * 内省:基于反射技术,用于操作Bean属性的一套api * @author lzqiangPC * */public class BeanUtils {//参数1 bean对象//参数2 要获得的Bean对象对应的属性名称public static Method getWriteMethod(Object beanObj, String name) {Method method = null;//使用内省技术来实现该方法try {//1. 分析Bean对象=> BeanInfoBeanInfo info = Introspector.getBeanInfo(beanObj.getClass());//2. 根据BeanInfo获得所有属性的描述器PropertyDescriptor[] pds = info.getPropertyDescriptors();//3. 遍历这些属性描述器if(pds!=null){for(PropertyDescriptor pd : pds){//判断当前遍历的描述器描述的属性是否是我们要找的属性//获得当前描述器描述的属性名称String pName = pd.getName();//使用要找的属性名称与当前描述器描述的属性名称比对if(pName.equals(name)){//比对一致=>找到了,获得写入属性的set方法method = pd.getWriteMethod();}}}//4. 返回找到的set方法} catch (IntrospectionException e) {e.printStackTrace();}//如果没有找到=>抛出异常提示用户 检查是否创建属性对应的set方法if(method==null){throw new RuntimeException("客官!请检查"+name+"属性的set方法是否创建!");}return method;}}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans><!-- 将A配置到配置文件中 --><bean name="A" class="cn.itcast.bean.A"  ><!-- 将A的属性配置,spring会自动将配置的值注入到A中 --><property name="name" value="123" ></property></bean><bean name="B" class="cn.itcast.bean.B" scope="prototype" ><!-- ref标识 要将Bean A注入 --><property name="a" ref="A" ></property></bean><bean name="C" class="cn.itcast.bean.C" scope="prototype"  ><!-- ref标识 要将Bean B注入 --><property name="b" ref="B" ></property></bean></beans>


0 0
原创粉丝点击