Spring笔记——模拟spring的bean管理原理以及依赖注入原理

来源:互联网 发布:苹果签名软件 编辑:程序博客网 时间:2024/05/01 19:53

有点时间,正好看了spring的教程,就试着写点东西模拟了下spring的这个简单过程! 

强力推荐传智播客,里面的视频资源很nice!


搭建spring环境,通过junit测试效果!

service包下的几个类,都比较简单 ,

PersonServiceDaoImpl:

package com.silence.service.bean;import com.silence.service.PersonServiceDao;public class PersonServiceDaoImpl implements PersonServiceDao {public void add() {System.out.println("dao 方法");}}


PersonServiceImpl:

package com.silence.service.bean;import com.silence.service.PersonService;import com.silence.service.PersonServiceDao;public class PersonServiceImpl implements PersonService {/* (non-Javadoc) * @see com.silence.service.bean.PersonService#save() */private PersonServiceDao personDao;private String name;public PersonServiceImpl(){//System.out.println("shilihua !");}public void save(){System.out.println("name="+name);personDao.add();}public void setPersonDao(PersonServiceDao personDao) {this.personDao = personDao;}public PersonServiceDao getPersonDao() {return personDao;}public void setName(String name) {this.name = name;}public String getName() {return name;}}
PersonService和PersonServiceDao:

package com.silence.service;public interface PersonService {public void save();}

package com.silence.service;public interface PersonServiceDao {public void add();}

Bean:

package com.silence.util;import java.util.List;/** * 装载Beans.xml文件下的Bean的描述 * @author silence * */public class Bean {private String id;private String className;private List<Property> propertys;public Bean(String id, String className ,List<Property> propertys) {this.setId(id);this.setClassName(className);this.setPropertys(propertys);}public void setClassName(String className) {this.className = className;}public String getClassName() {return className;}public void setId(String id) {this.id = id;}public String getId() {return id;}public void setPropertys(List<Property> propertys) {this.propertys = propertys;}public List<Property> getPropertys() {return propertys;}}
Property:

package com.silence.util;/** * 用来装载Beans.xml下的property描述 * @author silence * */public class Property {private String name;private String ref;private String value ;public void setName(String name) {this.name = name;}public String getName() {return name;}public void setRef(String ref) {this.ref = ref;}public String getRef() {return ref;}public Property(String name, String ref , String value) {this.name = name;this.ref = ref;this.value = value;}public void setValue(String value) {this.value = value;}public String getValue() {return value;}}
MyClassPathXmlApplicationContext:

package com.silence.util;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.io.File;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.commons.beanutils.ConvertUtils;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.XPath;import org.dom4j.io.SAXReader;/** * 模拟一个微量的spring容器 * @author silence * */public class MyClassPathXmlApplicationContext {private List<Bean> beans;private List<Property> propertys;private Map<String,Object> singleton;    //默认情况的下的单例模式!public MyClassPathXmlApplicationContext(String fileName){beans = new ArrayList<Bean>();singleton = new HashMap<String, Object>();//propertys = new ArrayList<Property>();this.readXML(fileName);this.instanceBean();this.injection();}/** * setter注入 * 实现bean的注入 */private void injection() {for(Bean bean : beans){Object temp = singleton.get(bean.getId());if(temp != null && bean.getPropertys() != null){  //对象为null或者属性个数为0的时候不进行注入操作try{//获取对象的属性描述,返回一个属性描述的数组PropertyDescriptor[] ps = Introspector.getBeanInfo(temp.getClass()).getPropertyDescriptors();  for(Property property:bean.getPropertys()){for(PropertyDescriptor p: ps){if(property.getName().equals(p.getName())){Method setter = p.getWriteMethod();if(setter != null){Object value = null;if(property.getRef() != null && !"".equals(property.getRef())){value = singleton.get(property.getRef());}else{//apache的提供的工具类,可以将String转化成已知的基本类型value = ConvertUtils.convert(property.getValue(), p.getPropertyType());}setter.setAccessible(true);setter.invoke(temp, value);}break;}}}}catch(Exception e){e.printStackTrace();}}}}/** * 对beans里面的对象进行实例化 * 并将初始化后的bean对象装入Map * @throws Exception  */private void instanceBean(){for(Bean bean:beans){if(bean.getClassName()!=null&&!"".equals(bean.getClassName().trim())){try {singleton.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());} catch (Exception e) {e.printStackTrace();}}}}/** * 解析XML * 使用的是dom4j * 将配置文件下的所有的bean节点的信息装入beans * @param fileName */private void readXML(String fileName) {SAXReader saxReader = new SAXReader();Document document = null;try {URL xmlPath = this.getClass().getClassLoader().getResource(fileName);document = saxReader.read(xmlPath);Map<String , String > nsMap = new HashMap<String , String>();nsMap.put("ns", "http://www.springframework.org/schema/beans");  //加入命名空间XPath xsub = document.createXPath("//ns:beans/ns:bean");  //创建beans/bean的查询路径xsub.setNamespaceURIs(nsMap);List<Element> elemBeans = xsub.selectNodes(document);  //查询document下的所有beanfor(Element e: elemBeans){String id = e.attributeValue("id");   //获取bean的id和class属性String className = e.attributeValue("class");XPath propertyXpath = document.createXPath("ns:property");propertyXpath.setNamespaceURIs(nsMap);List<Element> elemProp = propertyXpath.selectNodes(e);System.out.println(elemProp.size());if(elemProp.size() > 0 || elemProp != null){propertys = new ArrayList<Property>();for(Element e1:elemProp){String name = e1.attributeValue("name");String ref = e1.attributeValue("ref");String value = e1.attributeValue("value");System.out.println("property="+name +","+ref);propertys.add(new Property(name, ref ,value));}}else{propertys = null;}//这个propertys只有两种情况:里面有内容或者=nullbeans.add(new Bean(id, className,propertys));//System.out.println(id+","+className+","+propertys.size());} } catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}  }public Object getBean(String beanName){return this.singleton.get(beanName);}}
JUnit测试,记得导入junit的jar包!

import org.junit.BeforeClass;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.silence.service.PersonService;import com.silence.util.MyClassPathXmlApplicationContext;public class SpringTestCase {@BeforeClasspublic static void setUpBeforeClass()throws Exception{}@Test public void instanceSpring(){//ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");MyClassPathXmlApplicationContext ctx = new MyClassPathXmlApplicationContext("beans.xml");PersonService ps = (PersonService) ctx.getBean("personService");ps.save();}}

Beans.xml:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  <bean id="personService"  class="com.silence.service.bean.PersonServiceImpl" >    <!-- id不能接受特殊字符  ,name可以接受特殊字符 -->    <property name="personDao" ref="personDao"></property>    <property name="name" value="silence"></property>  </bean>  <bean id="personDao" class = "com.silence.service.bean.PersonServiceDaoImpl"></bean> </beans>

结果在我这里是正确通过的!

正在学习spring,目前还没发现有什么比较有意思的地方,功力还有得提高!欢迎探讨!