简单实现Spring的IOC容器

简单实现Spring的IOC容器

在学习Spring的时候,对IOC的实现比较感兴趣,在没有阅读源码前手动实现一个简单的IOC容器。

本文就通过dom4j解析xml文件,反射实例化对象,将对象存入hashmap中来简单实现一个IOC容器。

该容器只能解析通过属性注入的方式来实例化对象的xml文件(通过构造器方式注入来实例化对象的方法逻辑上差不多,都是使用反射,可以在本文代码的基础上进行调整实现)

导入dom4j

<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>

代码实现

解析xml文件,将实例化的对象存入HashMap中

package com.etime.common;



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

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @BelongsProject: spring
 * @BelongsPackage: com.etime.common
 * @Author: zhanghang
 * @CreateTime: 2022-10-18  21:08
 * @Description: 基础Spring容器,可以实现通过配置Spring的xml文件来实例化单例的pojo对象
 * 需要的技术点:解析xml文件,通过类名反射获取实例化对象,xml文件中的配置给对象的属性赋值,
 * 将赋值结束的对象存入hashmap,key为xml文件中的bean标签的id,value为对象
 * @Version: 1.0
 */
public class BaseIOC {
    private Map<String,Object> targetMap = new HashMap<>();
    private static final BaseIOC baseIOC = new BaseIOC();

    private BaseIOC() {
    }

    /**
     * @description: 获取单例对象
     * @author: zhanghang
     * @date: 2022/10/18 23:52
     * @param: []
     * @return: com.etime.common.BaseIOC
    **/
    public static BaseIOC getInstance(){
        return baseIOC;
    }

    /**
     * @description: 解析xml文件,同bean节点及其property获取bean对象,将其存储于map中
     * @author: zhanghang
     * @date: 2022/10/18 23:00
     * @param: [xmlPath]
     * @return: void
    **/
    public void parseXml(String xmlPath) throws Exception {
        //1.创建SAXReader对象,解析器
        SAXReader reader = new SAXReader();
        //2.创建对应的Document对象,加载xml
        Document document = null;
        document = reader.read(new File(xmlPath));
        //3.获取根节点
        Element rootElement = document.getRootElement();
        //4.获取根节点下的所有子节点
        Iterator rootIterator = rootElement.elementIterator();

        //5.遍历所有子节点
        while (rootIterator.hasNext()){
            //获取所有一级子节点的名称
            Element element = (Element) rootIterator.next();
            String name = element.getName();
            //若一级子节点的名称为bean
            Object o = null;
            String idValue = null;
            if ("bean".equals(name)){
                //获取标签为bean的id属性值
                Attribute idAttribute = element.attribute("id");
                idValue = idAttribute.getValue();
//                System.out.println(idValue);

                //获取标签为bean的class属性值,
                Attribute classAttribute = element.attribute("class");
                String classValue = classAttribute.getValue();
//                System.out.println(classValue);

                //通过属性值利用反射创建对象
                Class<?> beanClass = Class.forName(classValue);
                o = beanClass.newInstance();

                //获取标签为bean的所有子节点
                Iterator iterator = element.elementIterator();
                //遍历标签为bean的所有子节点
                while (iterator.hasNext()){
                    Element childElement = (Element) iterator.next();

                    //获取bean中子节点的名称
                    String childElementName = childElement.getName();
                    //子节点为property的可以通过属性注入
                    if ("property".equals(childElementName)){

                        //获取property标签的元素的属性值,name和value
                        Attribute nameAttribute = childElement.attribute("name");
                        String parameterName = nameAttribute.getValue();
                        Attribute valueAttribute = childElement.attribute("value");
                        String parameterValue = valueAttribute.getValue();

//                        System.out.println(parameterName);
//                        System.out.println(parameterValue);

                        //利用反射为实例化好的对象赋属性值
                        Field[] declaredFields = beanClass.getDeclaredFields();
                        for (Field field : declaredFields){
                            if (field.getName().equals(parameterName)){
                                Class<?> type = field.getType();
                                Method method = beanClass.getMethod(getSetterName(parameterName), type);
                                method.invoke(o,parameterValue);
                            }

                        }
                    }
                }

            }
            if (idValue!=null && o != null){
                targetMap.put(idValue,o);
            }
        }
    }

    /**
     * @description: 获取bean对象
     * @author: zhanghang
     * @date: 2022/10/18 23:52
     * @param: [beanId]
     * @return: java.lang.Object
    **/
    public Object getBean(String beanId){
        if (targetMap!=null && targetMap.size()!=0){
            return targetMap.get(beanId);
        }
        return null;
    }

    /**
     * @description: 通过属性名生成Setter方法名
     * @author: zhanghang
     * @date: 2022/10/18 23:16
     * @param: [parameterName]
     * @return: java.lang.String
    **/
    private static String getSetterName(String parameterName){
        char[] chars = parameterName.toCharArray();
        char c = Character.toUpperCase(chars[0]);
        chars[0] = c;
        String result = String.valueOf(chars);
        result = "set" + result;
        return result;
    }
}

简单IOC容器接口

package com.etime.common;

/**
 * @BelongsProject: spring
 * @BelongsPackage: com.etime.common
 * @Author: zhanghang
 * @CreateTime: 2022-10-18  22:49
 * @Description: 简单的IOC容器
 * @Version: 1.0
 */
public interface SimpleApplicationContext {
    public Object getBean(String beanId);
}

简单IOC容器接口实现类

package com.etime.common;

import java.lang.reflect.InvocationTargetException;

/**
 * @BelongsProject: spring
 * @BelongsPackage: com.etime.common
 * @Author: zhanghang
 * @CreateTime: 2022-10-18  22:55
 * @Description: IOC容器实现类
 * @Version: 1.0
 */
public class SimpleApplicationContextImpl implements SimpleApplicationContext{

    @Override
    public Object getBean(String beanId) {
        return BaseIOC.getInstance().getBean(beanId);
    }

    public SimpleApplicationContextImpl(String xmlPath) {
        try {
            BaseIOC.getInstance().parseXml(xmlPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试

实体类

package com.etime.pojo;

/**
 * @BelongsProject: spring
 * @BelongsPackage: com.etime.pojo
 * @Author: zhanghang
 * @CreateTime: 2022-10-18  15:57
 * @Description: Spring测试使用pojo对象
 * @Version: 1.0
 */
public class HelloSpring {
    private String name;
    private String addr;

    public String getName() {
        return name;
    }

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

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "HelloSpring{" +
                "name='" + name + '\'' +
                ", addr='" + addr + '\'' +
                '}';
    }
}

Spring-1.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">

    <bean id="helloSpring" class="com.etime.pojo.HelloSpring">
        <property name="name" value="张三"/>
        <property name="addr" value="成都"/>
    </bean>
</beans>

编写测试程序

package com.etime.test;

import com.etime.common.SimpleApplicationContext;
import com.etime.common.SimpleApplicationContextImpl;
import com.etime.pojo.HelloSpring;

/**
 * @BelongsProject: spring
 * @BelongsPackage: com.etime.test
 * @Author: zhanghang
 * @CreateTime: 2022-10-18  23:48
 * @Description: 测试简单IOC容器
 * @Version: 1.0
 */
public class TestBaseIOC {
    public static void main(String[] args) {
        SimpleApplicationContext simpleApplicationContext = new SimpleApplicationContextImpl("src/main/resources/spring-1.xml");
        HelloSpring helloSpring = (HelloSpring) simpleApplicationContext.getBean("helloSpring");
        System.out.println(helloSpring);
    }
}

测试结果

在这里插入图片描述

结语

至此,一个简单的SpringIOC容器就编写完成了,代码还有许多可以改进的地方,感谢阅读。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值