手写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遍