自己实现spring核心IOC部分
2015-11-18 11:04
706 查看
bean
config
parse
main
test;
utils
applicationContext.xml
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; } @Override public 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; } @Override public 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 遍历配置 初始化Bean if (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的Class String 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.Test public 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.Test public 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.Test public 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.Test public 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对象=> BeanInfo BeanInfo 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>
相关文章推荐
- eclipse使用—正则表达式匹配替换
- eclipse2studio
- eclipse+git
- java jvm学习笔记十(策略和保护域)
- SSH:Spring框架(利用注解实现spring基本配置详解)
- Java的位运算符详解实例——与(&)、非(~)、或(|)、异或(^)【转】
- java jvm学习笔记九(策略文件)
- java中的位移符
- java用spilt方法分割ip地址
- java精度问题
- Spring+SpringMVC+mybatis+easyui整合实例(一)实例介绍
- java jvm学习笔记八(实现jar包的代码签名)
- eclipse的activiti插件安装
- eclipse中 NoclassdefFoundError错误的分析
- JAVA--关键字final
- java初始化构造函数调用顺序
- Eclipse 快捷键
- java jdbc 学习
- 安装并配置JDK和ANT
- List分组