简单模拟Spring原生容器的实现

这篇文章详细描述了如何使用Spring的XML配置文件(如beans.xml)通过DOM4J库解析,利用反射创建JavaBean对象,并为其属性设置值,最后存储在自定义的容器中。作者还展示了如何通过ID从容器中获取对象实例。
摘要由CSDN通过智能技术生成

Spring配置xml-beans.xml 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置Monster对象/JavaBean-->
    <!--class属性:指定类的全路径-底层使用反射创建对象(指定无参构造器)-->
    <!--id属性:该对象在容器中的id,通过id获取到该对象-->
    <!--property属性:用于给该对象的属性赋值 value如果为空,则为默认值-->
    <bean class="spring.bean.Monster" id="monster01">
        <property name="id" value="1"/>
        <property name="name" value="牛魔王"/>
        <property name="skill" value="横冲直撞"/>
    </bean>
</beans>

 简单模拟Spring原生容器的底层实现机制

 1.使用了DOM4J库,得到节点,获取标签的配置的类的全路径

 2.通过反射创建对象实例

 3.获取property标签的属性值,通过对象的set方法为对象的属性赋值

 4.将bean标签配置的id当作key,当前对象实例当作value保存到HashMap容器中

 5.在静态代码块中,调用该方法,初始化容器

 6.定义getBean方法获取容器中的对象实例

package spring.context;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import spring.bean.Monster;

import java.io.File;
import java.util.HashMap;
import java.util.List;

/**
 * ClassName: HspApplicationContext
 * Package: spring.context
 * Description:
 * 使用DOM4J技术读取Src下的beans.xml配置文件的信息,并通过反射创建该对象实例
 * 并得到该对象的属性,通过set方法为该对象的属性赋值,并将id和该对象实例添加到容器中
 *
 * @Author 王文福
 * @Create 2024/1/31 0:41
 * @Version 1.0
 */
public class HspApplicationContext {

    //key Bean标签的id属性  value Monster对象
    private static HashMap<String, Object> container = new HashMap<>();


    /**
     * 通过id,得到该对象
     *
     * @param id:
     * @return Object
     * @author "卒迹"
     * @description TODO
     * @date 2:00
     */
    public static Object getBean(String id) {
        return container.get(id);
    }

    /**
     * 通过id,得到该对象
     *
     * @param id:
     * @return Object
     * @author "卒迹"
     * @description TODO
     * @date 2:00
     */
    public static <T> T getBean(String id, Class<T> aClass) {
        return (T) container.get(id);
    }

    static {
        try {
            getInstance();//初始化容器-存放xml标签配置的对象
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过反射,初始化JavaBean对象
     *
     * @param :
     * @return void
     * @author "卒迹"
     * @description TODO
     * @date 1:50
     */
    @Test
    public static void getInstance() throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        //1.得到类的加载路径
        String path = HspApplicationContext.class.getResource("/").getPath();
        SAXReader saxReader = new SAXReader();
        //2.通过类的加载路径,得到beans.xml
        Document document = saxReader.read(new File(path + "beans.xml"));
        System.out.println(document);
        //根节点
        Element rootElement = document.getRootElement();
        //子节点
        List<Element> elements = rootElement.elements();
        for (Element element : elements) {
            //验证获取的是否是bean标签
            if ("bean".equals(element.getName())) {
                //获取bean标签的属性class
                String beanPath = element.attributeValue("class");
                //通过反射该对象实例-必须提供无参构造器
                Monster monster = (Monster) Class.forName(beanPath.trim()).newInstance();
                //获取bean标签的属性id
                String beanId = element.attributeValue("id");
                //得到该Bean标签的子标签的property的属性name和value
                //name:该对象的属性   value:该对象的属性值
                List<Element> propertyList = element.elements("property");
                //得到该bean标签下的所有的子标签property
                for (Element property : propertyList) {
                    if ("property".equals(property.getName())) {
                        //得到所有property的属性值,通过对象的set方法为该对象赋值
                        String name = property.attributeValue("name");
                        String value = property.attributeValue("value");
                        //todo 验证属性名是否与对象的属性名一致...
                        if ("id".equals(name)) {
                            monster.setId(Integer.parseInt(value));
                        } else if ("name".equals(name)) {
                            monster.setName(value);
                        } else if ("skill".equals(name)) {
                            monster.setSkill(value);
                        }
                    }

                }
                //打印Monster-验证是否通过set方法赋值
                //System.out.println(monster);
                //将Monster对象以及id当作key和value保存到容器中
                //添加的条件:monster不为空并且Bean标签的id不为空,并且当前容器中不存在该对象
                if (null != monster && beanId != null && container.get(beanId) == null) {
                    container.put(beanId, monster);
                }


            }
        }
    }
}

代码测试:

package spring.test;

import spring.bean.Monster;
import spring.context.HspApplicationContext;

/**
 * ClassName: HspApplicationContextTest
 * Package: spring.test
 * Description:
 *
 * @Author 王文福
 * @Create 2024/1/31 2:06
 * @Version 1.0
 */
public class HspApplicationContextTest {
    public static void main(String[] args) {
        
        Monster monster01 = HspApplicationContext.getBean("monster01", Monster.class);
        System.out.println(monster01);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值