spring 依赖注入xml配置原理解析
2015-02-03 18:57
393 查看
本文实现了对spring的xml配置依赖注入的功能,也许并不是跟spring的实现一模一样,但是原理大致相同,本文旨在提供一种思路.....
1.添加相应的依赖包:
2.使用dom4j解析xml文档,通过反射获取相应的实例
4.配置文件
5.测试
1.添加相应的依赖包:
<dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.1</version> </dependency><dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency>
2.使用dom4j解析xml文档,通过反射获取相应的实例
public class Dom4jUtil { //单例 private static final Dom4jUtil util = new Dom4jUtil(); private SAXReader reader; private Document document; private Dom4jUtil(){ reader = new SAXReader(); } public static Dom4jUtil getInstance(){ return util; } //保存bean的id和class,id为key,value为反射获得的实例 private Map<String,Object> beans = new HashMap<String,Object>(); //保存bean的id和其需要注入的property的name和ref,id为外层map的key,name和ref分别为内层map的key,value private Map<String,Map<String,String>> propertys = new HashMap<String,Map<String,String>>(); /** * 根据路径获取document对象 * @param xmlPath * @return * @throws DocumentException */ public Map<String,Object> parseXml(String xmlPath) throws DocumentException{ document = reader.read(new File(xmlPath)); this.parseBean(document); return this.getBeansMap(document); } /** * 解析xml文档中的bean节点 * @param document */ @SuppressWarnings("unchecked") public void parseBean(Document document){ if(document==null){ return; } //获取根元素beans Element ele = document.getRootElement(); //使用xpath表达式查找所有的bean节点 List<Element> beanElements = ele.selectNodes("//beans/bean"); //保存bean里面的property节点 List<Element> propElements = null; //保存property的name和ref,name为key,ref为value Map<String,String> props = null; //保存bean的id属性 String id = null; //保存bean的class属性 String classpath = null; //获取的class Class<?> clz = null; for(Element beanElement:beanElements){ id = beanElement.attributeValue("id"); classpath = beanElement.attributeValue("class"); if(classpath==null||"".equals(classpath)){ throw new RuntimeException("The class attribute must be not null or ''"); } //如果没写id属性,默认id就是类名小写 if(id==null||"".equals(id)){ //截取类名 id = classpath.substring(classpath.lastIndexOf(".")+1); //类名首字母小写 id = id.replace(id.charAt(0), Character.toLowerCase(id.charAt(0))); } try { clz = Class.forName(classpath); } catch (ClassNotFoundException e) { throw new RuntimeException("The class "+classpath+ " is not found"); } id = classpath.substring(classpath.lastIndexOf(".")+1); //类名首字母小写 id = id.replace(id.charAt(0), Character.toLowerCase(id.charAt(0))); } try { clz = Class.forName(classpath); } catch (ClassNotFoundException e) { throw new RuntimeException("The class "+classpath+ " is not found"); } //判断该类是否已经被实例化 if(beans.containsKey(id)){ throw new RuntimeException("The class "+classpath+ " has already been instantiated"); }; try { //将bean进行保存 beans.put(id, clz.newInstance()); } catch (InstantiationException e) { throw new RuntimeException("The class "+classpath+" must be have default constructor"); } catch (IllegalAccessException e) { throw new RuntimeException("The class "+classpath+" must be have default constructor"); } //查找某个bean节点下的所有property节点 propElements = beanElement.selectNodes("property"); props = new HashMap<String,String>(); for(Element propElement:propElements){ props.put(propElement.attributeValue("name"), propElement.attributeValue("ref")); } //判断某个bean下是否有property,有就加到propertys里面 if(!props.isEmpty()){ propertys.put(id, props); } } } //注入bean,在调用改方法前需调用上面parseBean方法完成文档的解析 public Map<String,Object> getBeansMap(Document document){ if(beans==null){ return null; } //如果propertys为空,说明没有属性要注入,直接返回beans if(propertys.isEmpty()){ return beans; } //迭代解析好的bean(这些bean还没有完成属性注入) Set<String> idSet = propertys.keySet(); for(String id:idSet){ Object obj = this.injectProperty(id); //将注入好的bean重新放到beans里面 beans.put(id, obj); } return beans; } //注入bean的属性 private Object injectProperty(String id){ Map<String,String> props = null; Set<String> names = null; props = propertys.get(id); //迭代某个bean的property节点 names = props.keySet(); Object obj = beans.get(id); try { //name为property节点的name属性,props.get(name)为property节点的ref属性 for(String name:names){ //获取bean的所有属性描述 PropertyDescriptor[] pds = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors(); for(PropertyDescriptor pd:pds){ Method method = pd.getWriteMethod(); if(method!=null){ //判断变量名称是否和bean需要注入的name属性值是否一样 if(!pd.getName().equals(name)){ throw new RuntimeException("the class "+obj.getClass().getName()+" does not have such property '"+name+"'"); } //判断变量的类型和注入的类型是否有父子关系 if(!pd.getPropertyType().isAssignableFrom(beans.get(props.get(name)).getClass())){ throw new RuntimeException("the class "+obj.getClass().getName()+" can not be cast to "+pd.getPropertyType().getName()+""); }; method.invoke(obj, beans.get(props.get(name))); } } } } catch (IntrospectionException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return obj; } }3.需注入的dao,service
public interface IUserDao { void addUser(); }
public class UserDao implements IUserDao{ @Override public void addUser() { System.out.println("进行了新增操作"); } }
public interface IUserService { void addUser(); }
public class UserService implements IUserService{ private IUserDao userDao; //添加set方法进行注入 public void setUserDao(IUserDao userDao) { this.userDao = userDao; } @Override public void addUser() { userDao.addUser(); } }
4.配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean class="cn.edu.hbut.zw.spring.dao.impl.UserDao"></bean> <bean class="cn.edu.hbut.zw.spring.service.impl.UserService"> <property name="userDao" ref="userDao"/> </bean> </beans>
5.测试
public class SpringTest { @Test public void testXml(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserService us = (IUserService) context.getBean("userService"); us.addUser(); } }
相关文章推荐
- spring 依赖注入注解配置原理解析
- spring 控制反转和依赖注入 原理解析
- Spring配置文件解析-依赖注入
- Spring之依赖注入与XML配置文件
- Spring 学习笔记(四)—— XML配置依赖注入
- Spring配置文件解析--依赖注入
- 1、Spring DI xml配置文件方式解析原理
- 传智播客 Spring学习 xml配置依赖注入
- Spring配置文件解析-依赖注入
- Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
- Spring依赖注入的XML配置文件的实现思想(2)——简单的实现
- spring 框架中的依赖注入(IOC--设值注入)---使用xml简单配置文件---的具体实例的简单实现
- Spring——基于XML配置的依赖注入
- Spring (二)依赖注入原理 , bean 作用域, 其他配置
- Spring_使用XML配置文件实现依赖注入
- spring3: 依赖和依赖注入-xml配置-DI的配置
- Spring 3.0 学习-DI 依赖注入_创建Spring 配置-使用一个或多个XML 文件作为配置文件,使用自动注入(byName),在代码中使用注解代替自动注入,使用自动扫描代替xml中bea
- spring通过注解依赖注入和获取xml配置混合的方式
- 使用XPath解析xml实现简单的Spring IOC完成bean的依赖注入
- Spring依赖注入的XML配置文件的实现思想(1)——准备工作:如何读取XML的文件的内容