手撸spring-ioc,两种方法实现DI

本文档介绍了如何手动实现Spring的IoC容器,通过DOM4J解析XML配置文件和Java反射机制,创建并注入bean。详细步骤包括解析XML获取bean的id和class,以及通过反射创建和初始化对象。文中还给出了一个简单的应用案例,展示了如何读取配置文件并获取bean对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

手撸spring-ioc,两种方法实现DI

具备以下知识,看起来可能会更舒服:

  • dom4j解析xml文件
  • java反射机制

项目目录结构

在这里插入图片描述

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
    </dependencies>

DiyClassPathXmlApplicationContext

package ioc;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class DiyClassPathXmlApplicationContext {
    //配置文件基路径
    private static final String BASE_PATH = "D:\\java从头到脚\\springStudy\\diySpringIoc\\src\\main\\resources\\";
    //配置xml文件路径
    private String xmlPath;
    //定义此map用于存放bean对象,key为id,值为类对象
    private Map<String,Object> map = new HashMap<>();
    //构造此对象时传入xml文件配置路径
    public DiyClassPathXmlApplicationContext(String xmlPath) {
        this.xmlPath = xmlPath;
        try {
            creatBean();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //通过反射创建bean实例并且存入map集合中
    private void creatBean() throws FileNotFoundException, DocumentException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1. 获取文件的输入流
        FileInputStream fis = new FileInputStream(BASE_PATH+xmlPath);
        //2.创建xml读取工具对象
        SAXReader sr  = new SAXReader();
        //3.通过读取工具, 读取XML文档的输入流 , 并得到文档对象
        Document doc = sr.read(fis);
        //4. 通过文档对象 , 获取文档的根节点对象<beans>
        Element root = doc.getRootElement();
        //5. 通过根节点, 获取所有子节点<bean>
        List<Element> es = root.elements();
        if (!es.isEmpty()){
            for (Element e : es) {
                //获得bean的id
                String id = e.attributeValue("id");
                //获得bean的class类路径
                String classPath = e.attributeValue("class");
                //获取bean的子节点
                List<Element> elements = e.elements();
                //得到对应的class对象
                Class<?> clz = Class.forName(classPath);
                Object o = null;
                if (elements.isEmpty()){//如果bean没有property子节点则直接调用无参构造方法
                    //无参构造创建对应类的对象
                    o = clz.getConstructor().newInstance();
                }else {
                    o = clz.getConstructor().newInstance();
                    //得到此类的获取所有属性,方法一,属性赋值
                    Field[] fields = clz.getDeclaredFields();
                    for (int i = 0; i < elements.size(); i++) {
                        //获得节点对应的value值
                        String value = elements.get(i).attributeValue("value");
                        //开放访问权限
                        fields[i].setAccessible(true);
//                        Class<?> type = fields[i].getType();
//                        System.out.println(type);
                        fields[i].set(o,value);
                    }
                    //得到此类的所有方法,方法二,方法赋值
/*                    Method[] methods = clz.getMethods();
                    int j = 0;//慢指针,作为bean子节点的下标
                    for (int i = 0; i < methods.length; i++) {
                        if (methods[i].getName().startsWith("set")){//如果此方法是以set打头
                            //String pName = methods[i].getName().substring(3).toLowerCase(Locale.ROOT);
                            //System.out.println(pName);
                            if (j<elements.size()) {
                                Object value = elements.get(j).attributeValue("value");
                               System.out.println(value);
                                //调用set方法设置对象的属性值
                                methods[i].invoke(o, value);
                                //指针后移
                                j++;
                            }
                        }
                    }*/
                }
                map.put(id,o);
            }
        }
    }
    public Object getBean(String id){
        return map.get(id);
    }
}

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="student" class="pojo.Student">
        <property name = "idNum" value="1001"/>
        <property name = "name" value="Zy" />
        <property name = "school" value="湖理"/>
    </bean>
</beans>

student

package pojo;

public class Student {
    private String idNum;
    private String name;
    private String school;


    public Student() {
    }

    public String getIdNum() {
        return idNum;
    }

    public void setIdNum(String idNum) {
        this.idNum = idNum;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return "Student{" +
                "idNum='" + idNum + '\'' +
                ", name='" + name + '\'' +
                ", school='" + school + '\'' +
                '}';
    }
}

测试类

    @Test
    public void test2(){
        DiyClassPathXmlApplicationContext dca = new DiyClassPathXmlApplicationContext("application.xml");
        Student student = (Student) dca.getBean("student");
        System.out.println(student);
    }

运行截图
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值