手写spring简易版本,让你更好理解spring源码

首先我们要模拟spring,先搞配置文件,并配置bean

创建我们需要的类,beandefito,这个类是用来装解析后的bean,主要三个字段,id,class,scop,对应xml配置的属性

package org.zhw.ezspring.domain;
//解析后的bean
public class BeanDefinition {
    private String id;
    private String className;
    private String scope;

    public BeanDefinition(String id, String className, String scope) {
        this.id = id;
        this.className = className;
        this.scope = scope;
    }

    public BeanDefinition() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}

然后配置下我们要用的beandemo,这个后面我没用,但是懂的都懂,让大家更好理解下,xml中class,就是我们bean的路径,因为我们要用到反射。

package org.zhw.ezspring.domain;

public class DemoBean {
    private String Name;
    private String age;

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public DemoBean() {
    }

    public DemoBean(String name, String age) {
        Name = name;
        this.age = age;
    }
}

对了,我们还要使用一个jar包,这个可以用来解析xml文件,非常好用

然后我们开始模拟手写简易版spring,由于我已经全部写完了,就先把核心代码写在下面。

以防大家看不清,我把文件目录展示下

package org.zhw.ezspring.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.zhw.ezspring.domain.BeanDefinition;
import org.zhw.ezspring.domain.DemoBean;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class BeanFactory {
//    用来装beandefiton 的map
static ConcurrentHashMap<String, BeanDefinition> beanDiMap = new ConcurrentHashMap<>();
//    用来装单例bean的map
static HashMap<String, DemoBean> objectObjectHashMap = new HashMap<>();
//     实例化的时候,就加载bean
    public  BeanFactory(){
//        解析xml配置文件
        this("E:\\ideaspace\\ez-spring\\src\\resouces\\application.xml");
    }
    public BeanFactory(String path) {
        SAXReader reader = new SAXReader();
        try {
            // 读取XML文件
            Document document = reader.read(new File(path));

            // 获取根元素
            Element rootElement = document.getRootElement();

            // 遍历元素
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setClassName(element.attributeValue("className"));
                beanDefinition.setId(element.attributeValue("id"));
                beanDefinition.setScope(element.attributeValue("scope"));
                String scope = element.attributeValue("scope");
//                默认为单例
                if(scope!=null&&!"".equals(scope)){
                    beanDefinition.setScope("singleton");
                }
                System.out.println(beanDefinition);
//                放入beandefitionmap
                beanDiMap.put(beanDefinition.getId(),beanDefinition);
                iniSingletonObjects();

            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    private void iniSingletonObjects() {
//        1.遍历map
//        2.判断是不是单例,是就放入它
        Iterator<Map.Entry<String, BeanDefinition>> iterator = beanDiMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, BeanDefinition> entry = iterator.next();
            BeanDefinition value = entry.getValue();
            String scope = value.getScope();
            String id = value.getId();
            if (scope.equals("singleton")){
                DemoBean demoBean = new DemoBean();
                demoBean.setName("z");
                objectObjectHashMap.put(id,demoBean);
            }
        }
    }

    public   Object getBean(String id ) throws DocumentException {
//根据id,作为key去beandifitionmap中遍历,判断是单例还是多例,是单例就去单例map中找,不是则直接反射。
//        BeanFactory beanFactory = new BeanFactory();
        BeanDefinition beanDefinition = beanDiMap.get(id);
        if (Objects.isNull(beanDefinition)){
            throw new RuntimeException("beanFactory is null");
        }
        if ("singleton".equals(beanDefinition.getScope())){
            BeanDefinition beanDefinition1 = beanDiMap.get(id);

            return beanDefinition1;
        }
//        如何是多例,则使用反射创建bean
        try {
            Class<?> aClass = Class.forName(beanDefinition.getClassName());
            DemoBean o = (DemoBean) aClass.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("获取bean失败");
        }
        return null;
 }
// 通过class,来获取bean
    public  <T>T getBean(Class<T> classz){
        String name = classz.getName();
        Set<Map.Entry<String, BeanDefinition>> entries = beanDiMap.entrySet();
        Map.Entry<String, BeanDefinition> first = entries.stream().filter(x ->
                name.equals(x.getValue().getClassName())).findFirst().get();
        BeanDefinition value = first.getValue();
        if (value.getScope().equals("singleton")){
            return (T) beanDiMap.get(value.getId());
        }
//        不是单例就通过反射创建新的
        else {
            try {
                String id = value.getId();
                BeanDefinition beanDefinition = beanDiMap.get(id);
                Class<?> aClass = Class.forName(beanDefinition.getClassName());
                DemoBean o = (DemoBean) aClass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException("获取bean失败");
            }

        }


        return null;
 }

    public static void main(String[] args) {
        BeanFactory beanFactory = new BeanFactory();
        try {
            Object demo1 = beanFactory.getBean("demo1");
            Object demo2 = beanFactory.getBean("demo1");
            System.out.println(demo1==demo2);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

这是我们的结果,免得说我失败了,两个单例bean的地址完全相同

ok,让我们开始解析我手写的代码,非常简单易懂,哈哈

首先我们需要new,两个map,一个用来装解析bean后的beandefitonmap,一个用来装单例bean,因为spring原理,bean单例,就是要从单例map里面找得嘛。

然后我们首先要解析xml,new个工厂,在new工厂的过程中,我们就要对bean进行解析,包装为beandefiton,放到beandefitonmap中去。同时要默认为单例bean,所以没有加scope的bean要写为单例bean。还要对beandefinitionmap进行遍历,把单例bean,放入单例beanmap中

为什么我们可以遍历xml,是因为我们用了dom4j,百度ai直接搜,dom4j解析xml,我直接粘贴复制过来的

一个有参,一个无参,这个应该看得懂撒。

       private void iniSingletonObjects() {
//        1.遍历map
//        2.判断是不是单例,是就放入它
        Iterator<Map.Entry<String, BeanDefinition>> iterator = beanDiMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, BeanDefinition> entry = iterator.next();
            BeanDefinition value = entry.getValue();
            String scope = value.getScope();
            String id = value.getId();
            if (scope.equals("singleton")){
                DemoBean demoBean = new DemoBean();
                demoBean.setName("z");
                objectObjectHashMap.put(id,demoBean);
            }
        }
    }
public  BeanFactory(){
//        解析xml配置文件
        this("E:\\ideaspace\\ez-spring\\src\\resouces\\application.xml");
    }
    public BeanFactory(String path) {
        SAXReader reader = new SAXReader();
        try {
            // 读取XML文件
            Document document = reader.read(new File(path));

            // 获取根元素
            Element rootElement = document.getRootElement();

            // 遍历元素
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setClassName(element.attributeValue("className"));
                beanDefinition.setId(element.attributeValue("id"));
                beanDefinition.setScope(element.attributeValue("scope"));
                String scope = element.attributeValue("scope");
//                默认为单例
                if(scope!=null&&!"".equals(scope)){
                    beanDefinition.setScope("singleton");
                }
                System.out.println(beanDefinition);
//                放入beandefitionmap
                beanDiMap.put(beanDefinition.getId(),beanDefinition);
                iniSingletonObjects();

            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

然后我们就来写关于获取bean的方式,一个根据id获取,一个根据class获取。

根据id,先去beandefitonmap中去找,根据id,然后判断是不是空,还是单例bean,单例bean就去单例map中去找,多例则是用反射创建bean。

    public   Object getBean(String id ) throws DocumentException {
//根据id,作为key去beandifitionmap中遍历,判断是单例还是多例,是单例就去单例map中找,不是则直接反射。
//        BeanFactory beanFactory = new BeanFactory();
        BeanDefinition beanDefinition = beanDiMap.get(id);
        if (Objects.isNull(beanDefinition)){
            throw new RuntimeException("beanFactory is null");
        }
        if ("singleton".equals(beanDefinition.getScope())){
            BeanDefinition beanDefinition1 = beanDiMap.get(id);

            return beanDefinition1;
        }
//        如何是多例,则使用反射创建bean
        try {
            Class<?> aClass = Class.forName(beanDefinition.getClassName());
            DemoBean o = (DemoBean) aClass.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("获取bean失败");
        }
        return null;
 }

根据class获取bean,先用class获取bean的名字,然后我们去beandefitonmap中去找bean,然后判断是不是单例bean,这里我脑子有点混乱了,从beandftionmap中已经获取了bean,然后还要去单例map中获取,这不是多此一举吗?如果不是,自己通过反射,new一个新的bean

关于我通过class,获取bean,我感觉我写的很混乱,写的不是很好,如果错了,不要怪我哈,以供借鉴提醒。

public  <T>T getBean(Class<T> classz){
        String name = classz.getName();
        Set<Map.Entry<String, BeanDefinition>> entries = beanDiMap.entrySet();
        Map.Entry<String, BeanDefinition> first = entries.stream().filter(x ->
                name.equals(x.getValue().getClassName())).findFirst().get();
        BeanDefinition value = first.getValue();
        if (value.getScope().equals("singleton")){
            return (T) beanDiMap.get(value.getId());
        }
//        不是单例就通过反射创建新的
        else {
            try {
                String id = value.getId();
                BeanDefinition beanDefinition = beanDiMap.get(id);
                Class<?> aClass = Class.forName(beanDefinition.getClassName());
                DemoBean o = (DemoBean) aClass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException("获取bean失败");
            }

        }
        return null;
 }

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值