手写spring——基于xml方式

手写spring——基于xml方式(耐心的多看几遍就能看懂)
上一篇文章基于注解的方式通过构建spring容器来创建bean对象,这一篇用另外一种方式,基于xml的方式来实现

前期工作:

前期工作无先后顺序哦~

1.创建xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
 	<bean id="date" class="java.util.Date" lazy="true"></bean>
 	<bean id="obj" class="java.lang.Object" lazy="false"></bean>
</beans>

2.创建VO对象,来封装配置对象的信息
这里为了文章篇幅,把set和get方法去掉了

package com.java.spring.vo;
import java.io.Serializable;
//VO对象
public class BeanDefinition implements Serializable{

	private static final long serialVersionUID = 5107872838461301414L;
	private String id;
	private String pkgclass;
	private boolean lazy=false;
	@Override
	public String toString() {
		return "BeanDefinition [id=" + id + ", pkgclass=" + pkgclass + ", lazy=" + lazy + "]";
	}
}

正式开工

package com.java.spring.factory;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.sql.Date;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.java.spring.vo.BeanDefinition;

/**
 * @author dubl @date:2019年12月14日
 */
public class ClassPathXmlApplicationContext {
	private Map<String, BeanDefinition> beanMap = new HashMap<String, BeanDefinition>();
	private Map<String, Object> instanceMap=new HashMap<String, Object>();
	
	public ClassPathXmlApplicationContext(String file)throws Exception{
		//1.读取配置文件,类路径是bin下的
		InputStream in = getClass().getClassLoader().getResourceAsStream(file);
		//2.解析文件
		parse(in);
		//3.封装数据
	}
	
	//2.解析文件,本次xml的解析基于dom实现,会创建倒置的内存树
	private void parse(InputStream in) throws Exception {
		//1.创建解析器对象
		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		//2.解析流对象
		Document doc = builder.parse(in);
		//3.处理document
		processDocument(doc);
	}
	//3.处理document
	private void processDocument(Document doc) throws Exception {
		//1.获取所以bean元素
		NodeList list = doc.getElementsByTagName("bean");
		//2.迭代bean元素,对其配置信息进行封装
		for(int i=0;i<list.getLength();i++) {
			Node node = list.item(i);
			//一个node对应一个BeanDefinition
			BeanDefinition bd = new BeanDefinition();
			NamedNodeMap nMap = node.getAttributes();
			bd.setId(nMap.getNamedItem("id").getNodeValue());
			bd.setPkgclass(nMap.getNamedItem("class").getNodeValue());
			bd.setLazy(Boolean.valueOf(nMap.getNamedItem("lazy").getNodeValue()));
			//存储配置信息
			beanMap.put(bd.getId(), bd);
			//基于配置信息中国lazy属性的值
			if(!bd.getLazy()) {
				Object obj=newBeanInstance(bd.getPkgclass());
				instanceMap.put(bd.getId(), obj); 
			}
		}
	}
	//基于反射构建类实例对象
	public Object newBeanInstance(String pkgClass) throws Exception{
		Class<?> cls = Class.forName(pkgClass);
		Constructor<?> con = cls.getDeclaredConstructor();
		con.setAccessible(true);
		return con.newInstance();
	}
	public <T>T getBean(String key,Class<T> t) throws Exception{
		//1。判定当前instanceMap中是否有bean的实例
		Object obj = instanceMap.get(key);
		if(obj!=null)return (T)obj;
		//2.实例map中没有对象则创建对象
		newBeanInstance(t.getName());
		instanceMap.put(key, obj);
		return (T)obj;
	}
	public static void main(String[] args) throws Exception{
		//1.初始化spring容器
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-configs.xml");
		//2,从spring容器获取bean实例
		Object obj = ctx.getBean("obj", Object.class);
		Date date = ctx.getBean("date", Date.class);
		System.out.println(obj);
	}
}

执行过程梳理

1.创建spring容器,并准备读取配置文件

	//1.初始化spring容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-configs.xml");

2.读取类路径下的配置文件。返回值为流对象(这里提一句什么是类路径,类路径就是项目bin路径下的文件。读取这类下的文件可以用类加载器的方式去读取。 )

public ClassPathXmlApplicationContext(String file)throws Exception{
		//1.读取配置文件,类路径是bin下的
		InputStream in = getClass().getClassLoader().getResourceAsStream(file);
		//2.解析文件
		parse(in);
		//3.封装数据
	}

3.解析流对象。解析之前得先创建解析器对象。
解析器对象将流对象解析完以后封装成Document对象(文档对象–树对象。具体请百度Document对象)

//2.解析文件,本次xml的解析基于dom实现,会创建倒置的内存树
	private void parse(InputStream in) throws Exception {
		//1.创建解析器对象
		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		//2.解析流对象
		Document doc = builder.parse(in);
		//3.处理document
		processDocument(doc);
	}

4.处理Document对象,并存储配置信息

private void processDocument(Document doc) throws Exception {
		//1.获取所以bean元素
		NodeList list = doc.getElementsByTagName("bean");
		//2.迭代bean元素,对其配置信息进行封装
		for(int i=0;i<list.getLength();i++) {
			Node node = list.item(i);
			//一个node对应一个BeanDefinition
			BeanDefinition bd = new BeanDefinition();
			NamedNodeMap nMap = node.getAttributes();
			bd.setId(nMap.getNamedItem("id").getNodeValue());
			bd.setPkgclass(nMap.getNamedItem("class").getNodeValue());
			bd.setLazy(Boolean.valueOf(nMap.getNamedItem("lazy").getNodeValue()));
			//存储配置信息
			beanMap.put(bd.getId(), bd);
			//基于配置信息中国lazy属性的值
			if(!bd.getLazy()) {
				Object obj=newBeanInstance(bd.getPkgclass());
				instanceMap.put(bd.getId(), obj); 
			}
		}
	}

5.基于反射构建实例对象

	//基于反射构建类实例对象
	public Object newBeanInstance(String pkgClass) throws Exception{
		Class<?> cls = Class.forName(pkgClass);
		Constructor<?> con = cls.getDeclaredConstructor();
		con.setAccessible(true);
		return con.newInstance();
	}

6.获取Bean实例

public <T>T getBean(String key,Class<T> t) throws Exception{
		//1。判定当前instanceMap中是否有bean的实例
		Object obj = instanceMap.get(key);
		if(obj!=null)return (T)obj;
		//2.实例map中没有对象则创建对象
		newBeanInstance(t.getName());
		instanceMap.put(key, obj);
		return (T)obj;
	}

调试:

public static void main(String[] args) throws Exception{
		//1.初始化spring容器
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-configs.xml");
		//2,从spring容器获取bean实例
		Object obj = ctx.getBean("obj", Object.class);
		Date date = ctx.getBean("date", Date.class);
		System.out.println(obj);
		System.out.println(date);
	}

每篇文章一句话:

我们究竟是活了365天,还是活了一天,重复了364遍

你可能感兴趣的:(Spring)