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();
}
}
}