手写Spring框架
1 如何理解Spring中两个map
- 一个map用于存储bean的配置信息
- 一个map用于存储bean的实例信息
2.编写代码
1.创建BeanDefinition类用来存储配置文件信息
public class BeanDefinition implements Serializable {
private String id;
private String pkgClass;
private Boolean lazy;
//get set toString
}
2.创建配置文件 spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="date" class="java.util.Date" lazy="true"/>
<bean id="obj" class="java.lang.Object" lazy="false"/>
</beans>
3.创建ClassPathXmlApplicationContext类用于读取配置文件并创建对象
/**
* @Author: Rwenjie
* @ProjectName: springframework
* @Description: 用于读取配置文件并创建对象
* @Date: 2020/7/28 16:53
**/
public class ClassPathXmlApplicationContext {
/*
* 通过此map存储配置文件中定义的Bean对象的配置信息
*/
private Map<String, BeanDefinition> beanMap = new HashMap<String, BeanDefinition>();
/*
* 通过此map存储Bean实例
*/
private Map<String, Object> instanceMap = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String file) {
//1.读取配置文件 getClassLoader() -获取根目录
InputStream in = getClass().getClassLoader().getResourceAsStream(file);
//2.解析文件
//3.分装数据
}
/*
* Class<T> t:希望返回类型
*/
public <T>T getBean(String key, Class<T> t){
return null;
}
}
4.成功读取配置文件并获取bean标签测试
/**
* @Author: Rwenjie
* @ProjectName: springframework
* @Description: 用于读取配置文件并创建对象
* @Date: 2020/7/28 16:53
**/
public class ClassPathXmlApplicationContext {
/*
* 通过此map存储配置文件中定义的Bean对象的配置信息
*/
private Map<String, BeanDefinition> beanMap = new HashMap<String, BeanDefinition>();
/*
* 通过此map存储Bean实例
*/
private Map<String, Object> instanceMap = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String file) {
//1.读取配置文件 getClassLoader() -获取根目录
InputStream in = getClass().getClassLoader().getResourceAsStream(file);
//2.解析文件
try {
parse(in);
} catch (Exception e) {
e.printStackTrace();
}
//3.分装数据
}
/*
* parse 此方法用来解析xml配置文件
* 市场主流的xml解析 dom(标准) dom4j sax pull....
*/
private void parse(InputStream in) throws Exception {
//1. 创建解析器对象
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
//2.解析流对象 导w3c下的包
Document doc = builder.parse(in);
//3.处理doc
processDocument(doc);
}
/*
* processDocument 此方法用来读取配置信息
*/
private void processDocument(Document doc){
//1.获取所有的bean元素
NodeList list = doc.getElementsByTagName("bean");
//2.迭代bean元素
for (int i=0; i<list.getLength(); i++){
//一个Node对象接收一个bean标签
Node node = list.item(i);
//测试标签名是否成功
System.out.println(node.getNodeName());
}
}
/*
* Class<T> t:希望返回类型
*/
public <T>T getBean(String key, Class<T> t){
return null;
}
}
public class TestMian {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("Spring-config.xml");
}
}
5.得到bean标签属性的值,并存到Map中
public class ClassPathXmlApplicationContext {
/*
* 通过此map存储配置文件中定义的Bean对象的配置信息
*/
private Map<String, BeanDefinition> beanMap = new HashMap<String, BeanDefinition>();
/*
* 通过此map存储Bean实例
*/
private Map<String, Object> instanceMap = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String file) {
//1.读取配置文件 getClassLoader() -获取根目录
InputStream in = getClass().getClassLoader().getResourceAsStream(file);
//2.解析文件
try {
parse(in);
} catch (Exception e) {
e.printStackTrace();
}
//3.分装数据
}
/*
* parse 此方法用来解析xml配置文件
* 市场主流的xml解析 dom(标准) dom4j sax pull....
*/
private void parse(InputStream in) throws Exception {
//1. 创建解析器对象
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
//2.解析流对象 导w3c下的包
Document doc = builder.parse(in);
//3.处理doc
processDocument(doc);
}
/*
* processDocument 此方法用来读取配置信息
*/
private void processDocument(Document doc){
//1.获取所有的bean元素
NodeList list = doc.getElementsByTagName("bean");
//2.迭代bean元素
for (int i=0; i<list.getLength(); i++){
//一个Node对象接收一个bean标签
Node node = list.item(i);
//测试标签名是否成功
System.out.println(node.getNodeName());
//一个Node对 BeanDefinition对象
BeanDefinition bd = new BeanDefinition();
//获取bean标签的属性、
NamedNodeMap nodeMap = node.getAttributes();
System.out.println(nodeMap.getNamedItem("id").getNodeValue());
bd.setId(nodeMap.getNamedItem("id").getNodeValue());
bd.setPkgClass(nodeMap.getNamedItem("class").getNodeValue());
bd.setLazy(Boolean.valueOf(nodeMap.getNamedItem("lazy").getNodeValue()));
//存储配置信息
beanMap.put(bd.getId(), bd);
System.out.println(beanMap );
}
}
/*
* Class<T> t:希望返回类型
*/
public <T>T getBean(String key, Class<T> t){
return null;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JsG4cCGf-1595940665533)(F:\Typora\img\image-20200728192905052.png)]
6.判断是否延迟加载,利用反射
public class ClassPathXmlApplicationContext {
/*
* 通过此map存储配置文件中定义的Bean对象的配置信息
*/
private Map<String, BeanDefinition> beanMap = new HashMap<String, BeanDefinition>();
/*
* 通过此map存储Bean实例
*/
private Map<String, Object> instanceMap = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String file) {
//1.读取配置文件 getClassLoader() -获取根目录
InputStream in = getClass().getClassLoader().getResourceAsStream(file);
//2.解析文件
try {
parse(in);
} catch (Exception e) {
e.printStackTrace();
}
//3.分装数据
}
/*
* parse 此方法用来解析xml配置文件
* 市场主流的xml解析 dom(标准) dom4j sax pull....
*/
private void parse(InputStream in) throws Exception {
//1. 创建解析器对象
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
//2.解析流对象 导w3c下的包
Document doc = builder.parse(in);
//3.处理doc
processDocument(doc);
}
/*
* processDocument 此方法用来读取配置信息
*/
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对象接收一个bean标签
Node node = list.item(i);
//测试标签名是否成功
System.out.println(node.getNodeName());
//一个Node对 BeanDefinition对象
BeanDefinition bd = new BeanDefinition();
//获取bean标签的属性、
NamedNodeMap nodeMap = node.getAttributes();
System.out.println(nodeMap.getNamedItem("id").getNodeValue());
bd.setId(nodeMap.getNamedItem("id").getNodeValue());
bd.setPkgClass(nodeMap.getNamedItem("class").getNodeValue());
bd.setLazy(Boolean.valueOf(nodeMap.getNamedItem("lazy").getNodeValue()));
//存储配置信息
beanMap.put(bd.getId(), bd);
//基于配置信息中lazy属性的值判断是否延迟加载
if(!bd.getLazy()){
Object object = newBeanIntance(bd.getPkgClass());
instanceMap.put(bd.getId(), object);
}
}
System.out.println(beanMap );
}
/*
* 此方法用来反射创建对象
*/
private Object newBeanIntance(String pkgClass) throws Exception{
Class<?> cls = Class.forName(pkgClass);
//找到无参构造方法创建对象
Constructor<?> con = cls.getDeclaredConstructor(null);
//如果构造函数私有化也可以起执行
con.setAccessible(true);
//通过无参构造函数创建对象
return con.newInstance();
}
/*
* Class<T> t:希望返回类型
*/
public <T>T getBean(String key, Class<T> t){
return null;
}
}
7.编写getBean方法用来返回对象
public <T>T getBean(String key, Class<T> t) {
try {
//1.判断当前instanceMap中是否有Bean的实例
Object object = instanceMap.get(key);
if(object!=null){
return (T)object;
}
//2.实例map中没有对象则创建对象,然后存储到map
object = newBeanInstance(t.getName());
System.out.println(t.getName());
instanceMap.put(key, object);
return (T)object;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
8.获取对象
public class TestMian {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("Spring-config.xml");
Object obj = ac.getBean("obj", Object.class);
Date date = ac.getBean("date", Date.class);
System.out.println(obj);
System.out.println(date);
}
}