1、定义BeanDefinition,另外bean里面还有 <property>节点,这里把它抽象成PropertyDefinition
代码如下:
package com.laoxu.test.day02.springDemo.parseXml; /** * 在读取配置信息的时候,当读到<bean>节点的时候,需要把节点中的id,class 等等属性共同组成一个对象, * 这里定义成BeanDefinition,另外bean里面还有 <property>节点,这里把它抽象成PropertyDefinition */ import java.util.ArrayList; import java.util.List; /** * 1、BeanDefinition获取bean对象的id和对应的class的路径 2、PropertyDefinition * 表示bean下面的property属性 */ public class BeanDefinition { private String className; private String id; private List<PropertyDefinition> definitions = new ArrayList<PropertyDefinition>(); public BeanDefinition(String className, String id) { super(); this.className = className; this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getId() { return id; } public void setId(String id) { this.id = id; } public List<PropertyDefinition> getDefinitions() { return definitions; } public void setDefinitions(List<PropertyDefinition> definitions) { this.definitions = definitions; } } package com.laoxu.test.day02.springDemo.parseXml; /** * bean里面有 <property>节点,这里把它抽象成PropertyDefinition */ public class PropertyDefinition { public PropertyDefinition() { } private String name; private String ref; public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2、首先配置XML文件,创建相应的bean对象,代码如下:
<?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.0.xsd"> <!-- 把业务bean交给Spring来管理,bean 的id是唯一的,name属性也是为bean起名的,id本身就是xml的属性 但id的值是不能包含特殊字符的比如/,name是 可以指定特殊字符 bean配置好之后,bean就会有spring容器来帮我们创建和维护 --> <bean id="personService" class="com.laoxu.test.day02.springDemo.entity.PersonServiceBean" > <property name="personDao" ref="personDao"></property> </bean> <bean id="personDao" class="com.laoxu.test.day02.springDemo.dao.PersonDao"> </bean> </beans>
创建对象类代码,其中可以包含业务等信息:
package com.laoxu.test.day02.springDemo.entity; import com.laoxu.test.day02.springDemo.dao.PersonDao; /** * bean对象 */ public class PersonServiceBean { private PersonDao personDao; public void say(String name){ System.out.println("this is the person say:" + name); if(personDao==null){ System.out.println("personDao is null"); return ; } personDao.getDB(name); } public PersonDao getPersonDao() { return personDao; } public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } }
package com.laoxu.test.day02.springDemo.dao; public class PersonDao { public void getDB(String name){ System.out.println("this is the DB:"+name); } }
3、通过Dom4j读取XML的配置文件。代码如下:
package com.laoxu.test.day02.springDemo.parseXml; import java.net.URL; import java.util.ArrayList; 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.XPath; import org.dom4j.io.SAXReader; /** * 解析XML文件工具类 */ public class ParseXMLUtil { @SuppressWarnings("unchecked") public static List<BeanDefinition> readXML(String name) throws DocumentException{ SAXReader saxReader = new SAXReader();//创建读取器 Document document = null; /* * 注意此处不能使用this,因为方法是静态方法,解决方法:ParseXMLUtil.class */ URL url = ParseXMLUtil.class.getClassLoader().getResource(name); if(url==null){ System.out.println("this url is null"); return null; } document = saxReader.read(url);//读取文件内容 Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath path = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径 path.setNamespaceURIs(nsMap);//设置命名空间, 其中的//ns:是根 List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); List<Element> elements = path.selectNodes(document);//获取当前文档下的所有bean节点 List<Element> elementss = null;//Property属性集合 List<PropertyDefinition> propertyDefinitions = null; PropertyDefinition propertyDefinition = null; BeanDefinition beanDefinition = null; for (Element element : elements) { beanDefinition = new BeanDefinition(element.attributeValue("class"), element.attributeValue("id"));//获取class属性与id属性 /* * 获取property属性集合 */ elementss = element.elements(); propertyDefinitions = new ArrayList<PropertyDefinition>(); for (Element ele : elementss) { propertyDefinition = new PropertyDefinition(); propertyDefinition.setName(ele.attributeValue("name")); propertyDefinition.setRef(ele.attributeValue("ref")); propertyDefinitions.add(propertyDefinition); } beanDefinition.setDefinitions(propertyDefinitions); beanDefinitions.add(beanDefinition); } return beanDefinitions; } }
4、动态生成bean对象,并且通过set方法注入对象。代码如下:
package com.laoxu.test.day02.springDemo.parseXml; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.DocumentException; /** * 通过读取的XML配置信息,获取相应的Bean对象 * */ public class ApplicationContextBeanUtil { private String fileName; private List<BeanDefinition> beanDefinitions; @SuppressWarnings("unused") private ApplicationContextBeanUtil(){ } public ApplicationContextBeanUtil(String fileName) throws DocumentException{ super(); this.fileName = fileName; init(); } public void init() throws DocumentException{ /* * 读取XML文件 */ beanDefinitions = ParseXMLUtil.readXML(fileName); injectObject(beanDefinitions); } public Object getBeanForUser(String beanID){ return injectObject(beanDefinitions).get(beanID); } /* * 获取Bean对象 */ private static Object getBean(String beanName,List<BeanDefinition> beanDefinitions){ if(beanName == null) return beanName; Map<String, Object> beans = instanceBeans(beanDefinitions); return beans.get(beanName); } /* * 获取bean的实例对象,存放到Map中 */ public static Map<String,Object> instanceBeans(List<BeanDefinition> beanDefinitions){ Map<String,Object> beans = new HashMap<String, Object>(); if(beanDefinitions == null||beanDefinitions.size() == 0) return beans; /* * 循环将类实例化 */ for (BeanDefinition beanDefinition : beanDefinitions) { if(beanDefinition.getId()!=null&&beanDefinition.getClassName()!=null){ try { try { //通过Class.forName(className).newInstance()创建对象 /* * Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 * Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段 */ beans.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } return beans; } /* * 依赖注入的方法,实现对象的依赖注入(通过set方法实现注入) */ public static Map<String, Object> injectObject(List<BeanDefinition> beanDefinitions){ Map<String, Object> beans = new HashMap<String, Object>();//经过注入的bean对象的哈希 if(beanDefinitions==null||beanDefinitions.size()==0) return null; for (BeanDefinition beanDefinition : beanDefinitions) { Object bean = getBean(beanDefinition.getId(), beanDefinitions); if(bean == null) return null; try { //可以获取当前bean下的所有属性,包括get、set方法 PropertyDescriptor[] pds = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); //遍历当前配置对象中的所有的property属性 for (PropertyDefinition propertyDefinition : beanDefinition.getDefinitions()) { //遍历当前bean对象中的所有属性 for (PropertyDescriptor propertyDescriptor : pds) { /* * 通过比较配置文件中的property的name值与当前bean对象中的name值是否相同 * 来获取当前的set方法,将属性注入 */ if(propertyDefinition.getName().equals(propertyDescriptor.getName())){ Method setter = propertyDescriptor.getWriteMethod(); if(setter==null) return null; setter.setAccessible(true); //根据当前set方法的属性,获取当前property下的ref所引的对象 Object value = instanceBeans(beanDefinitions).get(propertyDefinition.getRef()); try { setter.invoke(bean, value); beans.put(beanDefinition.getId(), bean); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } } catch (IntrospectionException e) { e.printStackTrace(); } } return beans; } public List<BeanDefinition> getBeanDefinitions() { return beanDefinitions; } public void setBeanDefinitions(List<BeanDefinition> beanDefinitions) { this.beanDefinitions = beanDefinitions; } }
5、测试类:
package com.laoxu.test.day02.springDemo.test; import org.dom4j.DocumentException; import com.laoxu.test.day02.springDemo.entity.PersonServiceBean; import com.laoxu.test.day02.springDemo.parseXml.ApplicationContextBeanUtil; /** * 测试类 * @author Administrator * */ public class SpringTest { public static void main(String[] args) { String fileName = "com/laoxu/test/day02/springDemo/config/bean.xml"; try { ApplicationContextBeanUtil contextBeanUtil = new ApplicationContextBeanUtil(fileName); PersonServiceBean bean = (PersonServiceBean) contextBeanUtil.getBeanForUser("personService"); bean.say("lily"); } catch (DocumentException e) { e.printStackTrace(); } } }