通过DOM解析假装实现Spring中Bean注入
一、案例需求
通过反射的形式去创建对象,只要通过传入xml配置,我们使用DOM解析xml的方式,去读取数据,根据数据去创建对象和简单属性赋值!该案例在于更好的理解Spring中的IOC容器
本文参考博文:XML解析之DOM解析详解
二、步骤结解析
- 创建实体类
- 创建application.xml文件
- 解析xml文件
- 根据反射去创建bean对象
- 将xml配置的中property节点的数据赋给创建好bean
- 测试
三、代码实现
1. 创建实体类
该实体类的set方法都要是Object,因为我们不知到从xml读取的文件是什么类型!
public class Student {
private int sid;
private String name;
private String sex;
public Student() {
super();
}
public Student(int sid, String name, String sex) {
super();
this.sid = sid;
this.name = name;
this.sex = sex;
}
// 注意:所有set方法的参收都要是Object类型的,这里需要强转一下
public int getSid() {
return sid;
}
public void setSid(Object sid) {
this.sid = Integer.parseInt(sid.toString());
}
public String getName() {
return name;
}
public void setName(Object name) {
this.name = (String) name;
}
public String getSex() {
return sex;
}
public void setSex(Object sex) {
this.sex = (String) sex;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", name=" + name + ", sex=" + sex + "]";
}
}
2. 创建ApplicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean name="student" class="model.Student">
<property name="sid" value="001"></property>
<property name="name" value="name"></property>
<property name="sex" value="男"></property>
</bean>
</beans>
3. 解析xml文件、创建对象、并给对象赋值
该类通过注释进行一步步解析,可以仔细看一下注释!
public class MyApplicationContext{
// 使用多线程赋值的话建议使用ConcurrentHashMap
// private Map<String,Object> beansHolder = new ConcurrentHashMap<String, Object>();
private Map<String,Object> beansMap = new HashMap<String, Object>();
private String xmlPath;
public MyApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
analysisXML();
}
// DOM解析xml
public void analysisXML() {
// 找了一个工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
// 工厂里的一个工人
DocumentBuilder buider = factory.newDocumentBuilder();
// 工人去读取xml文件 ,然后得到了一个读取到的文件
Document document = buider.parse(xmlPath);
// 读取所有bean节点
NodeList nodeBean = document.getElementsByTagName("bean");
// 循环遍历nodeBean
for(int i = 0; i < nodeBean.getLength();i++) {
// 得到所有bean属性
NamedNodeMap namedNodeMap = nodeBean.item(i).getAttributes();
// 获取bean节点
Element element = (Element)nodeBean.item(i);
// 获取bean节点下所有property元素
NodeList childNodes = element.getElementsByTagName("property");
// 将获取到的bean所有属性和bean节点下所有property元素传递到创建bean方法中继续使用
createBean(namedNodeMap,childNodes);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 创建bean
public void createBean(NamedNodeMap namedNodeMap,NodeList childNodes) {
String className = null; // bean节点中的name属性值
String class_val = null; // bean节点中的class属性值
// 遍历bean的所有属性
for(int i = 0; i < namedNodeMap.getLength();i++) {
Node node = namedNodeMap.item(i);
// 取出name属性值
if("name".equalsIgnoreCase(node.getNodeName())) {
className = node.getNodeValue();
}
// 取出class属性值
if("class".equals(node.getNodeName())){
class_val = node.getNodeValue();
}
// 判断二者都不为空
if(!"".equals(className) && !"".equals(class_val)) {
// 去创建bean,并存入map集合
setBean(className,class_val);
}else {
System.out.println("参数为空!");
}
}
// 属性赋值(bean节点下所有property元素,bean的class属性值,bean的name属性值)
setProperty(childNodes,class_val,className);
}
// 注入属性值
public void setProperty(NodeList childNodes,String class_val,String className) {
String name_val = null; //property元素中的name属性值
Object value_val = null; //property元素中的value属性值
// 遍历所有property元素
for(int i = 0; i < childNodes.getLength();i++) {
// 获取每个property所有属性
NamedNodeMap attributes = childNodes.item(i).getAttributes();
// 遍历property的所有属性
for(int j = 0; j < attributes.getLength();j++) {
// 得到一个属性节点
Node node = attributes.item(j);
if(node!= null) {
// 得到name的值
if("name".equals(node.getNodeName())) {
name_val = node.getNodeValue();
}
// 得到value的值
if("value".equals(node.getNodeName())){
value_val = node.getNodeValue();
}
}
}
try {
// 根据bean的class属性值,获取指定类的构造器
Class<?> clazz = Class.forName(class_val);
// 去查找set方法,传入参数类型
Method method = clazz.getMethod("set"+toFirst(name_val),Object.class);
// 然后去执行set方法,指定实体类,传入该方法所需的参数
method.invoke(beansMap.get(className),value_val);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 首字母大写
public String toFirst(String str) {
if(str!=null&&str.length()>0){
str=str.substring(0, 1).toUpperCase() + str.substring(1);
}
return str;
}
// 注入bean
public void setBean(String beanNname,String clazzPath) {
try {
// 通过反射创建bena对象
Object obj = Class.forName(clazzPath).newInstance();
// 将创建的bean存入map集合
beansMap.put(beanNname,obj);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取bean对象
public Object getBean(String beanName) {
return beansMap.get(beanName);
}
}
3. 测试
public class MainTest {
public static void main(String[] args) {
MyApplicationContext context = new MyApplicationContext("src/application.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
}