Java通过DOM解析假装实现Spring中Bean注入

Posted GaoYang-笔迹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java通过DOM解析假装实现Spring中Bean注入相关的知识,希望对你有一定的参考价值。

通过DOM解析假装实现Spring中Bean注入

一、案例需求

通过反射的形式去创建对象,只要通过传入xml配置,我们使用DOM解析xml的方式,去读取数据,根据数据去创建对象和简单属性赋值!该案例在于更好的理解Spring中的IOC容器
本文参考博文:XML解析之DOM解析详解

二、步骤结解析

  1. 创建实体类
  2. 创建application.xml文件
  3. 解析xml文件
  4. 根据反射去创建bean对象
  5. 将xml配置的中property节点的数据赋给创建好bean
  6. 测试

三、代码实现

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

以上是关于Java通过DOM解析假装实现Spring中Bean注入的主要内容,如果未能解决你的问题,请参考以下文章

【面试题解析】从 Vue 源码分析 key 的作用

反射-Spring管理Bean,注入Bean属性的反射机制。

Java中Xml解析(四种方法)

JAVA中使用DOM解析XML文件

Spring使用Spring发送邮件

spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)