手写一个简单的IOC容器

手写一个简单的IOC容器

原文 http://localhost:4000/2020/02/25/SSM/spring/%E6%89%8B%E5%86%99%E4%B8%80%E4%B8%AA%E5%88%9D%E7%BA%A7%E7%9A%84IOC%E5%AE%B9%E5%99%A8/#more

说明

首先我们都知道,Spring框架中两个最重要的组件就是IOC和AOP。IOC 即 inversion of control 控制反转。Aop即 Aspect Oriented Programming 面向切面编程。那么我们这里就来手写一个简单的IOC容器。这里主要使用 xml配置的方式来实现IOC容器。

前置知识

手撸一个IOC容器需要先掌握好 XML文件解析Java反射知识。

行了,下面我们就开始了。

项目搭建

创建项目

使用普通的maven搭建一个项目。

导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>

    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
</dependencies>
实体类
package com.ooyhao.pojo;
import lombok.Data;
import java.io.Serializable;

@Data
public class User implements Serializable {

    private byte age;
    private Byte ageB;

    private short height;
    private Short heightS;

    private int id;
    private Integer idI;

    private long weight;
    private Long weightL;

    private char sex;
    private Character sexC;

    private float salary;
    private Float salaryF;

    private double buy;
    private Double buyD;

    private boolean successB;
    private Boolean success;

    private String name;
}
spring配置文件
<?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="user" class="com.ooyhao.pojo.User">
        <property name="age" value="2"/>
        <property name="ageB" value="20"/>
        <property name="height" value="170"/>
        <property name="heightS" value="1700"/>
        <property name="id" value="1"/>
        <property name="idI" value="10"/>
        <property name="weight" value="60"/>
        <property name="weightL" value="600"/>
        <property name="sex" value="m"/>
        <property name="sexC" value="f"/>
        <property name="salary" value="7500.5"/>
        <property name="salaryF" value="9000.5"/>
        <property name="buy" value="10.05"/>
        <property name="buyD" value="100.5"/>
        <property name="success" value="false"/>
        <property name="successB" value="true"/>
        <property name="name" value="欧阳"/>
    </bean>
</beans>
自定义ApplicationContext
/**
 * 简单手写一个IOC容器
 */
public class MyApplicationContext implements ApplicationContext {
    private static Map<String,Object> beansContainer = new HashMap<>();

    public MyApplicationContext(String path){
        //构造器中处理
        //处理ClassPath下的文件。
        ClassPathResource resource = new ClassPathResource(path);
        //利用DOM4J解析XML文件
        SAXReader reader = new SAXReader();
        try {
            //读取xml文件,获取到文档
            Document document = reader.read(resource.getInputStream());
            //根目录beans
            Element beansElement = document.getRootElement();
            //迭代beans获取多个bean
            Iterator<Element> beansIter = beansElement.elementIterator();
            while(beansIter.hasNext()){
                //单个bean
                Element beanElement = beansIter.next();
                //id
                String id = beanElement.attributeValue("id");
                //完整的类名
                String className = beanElement.attributeValue("class");
                //通过className反射出一个对象
                Class<?> aClass = Class.forName(className);
                //获取无参数的构造器
                Constructor<?> constructor = aClass.getConstructor();
                //利用无参数的构造器创建实例
                Object o = constructor.newInstance();
                //迭代bean获取property
                Iterator<Element> beanIter = beanElement.elementIterator();
                while (beanIter.hasNext()){
                    Element property = beanIter.next();
                    //属性名
                    String fieldName = property.attributeValue("name");
                    //属性值
                    String fieldValue = property.attributeValue("value");
                    //根据属性名获取属性对象
                    Field field = aClass.getDeclaredField(fieldName);
                    //属性的类型
                    Class<?> fieldType = field.getType();
                    //拼接set方法名
                    String setMethodName = "set" + fieldName.substring(0,1).toUpperCase()+ fieldName.substring(1);
                    //获取方法对象
                    Method method = aClass.getMethod(setMethodName, fieldType);

                    Object val = fieldValue;
                    switch (fieldType.getName()){
                        case "int":
                        case "java.lang.Integer":
                            val = Integer.valueOf(fieldValue);
                            break;
                        case "boolean":
                        case "java.lang.Boolean":
                            val = Boolean.valueOf(fieldValue);
                            break;
                        case "char":
                        case "java.lang.Character":
                            val = fieldValue.charAt(0);
                            break;
                        case "long":
                        case "java.lang.Long":
                            val = Long.valueOf(fieldValue);
                            break;
                        case "double":
                        case "java.lang.Double":
                            val = Double.valueOf(fieldValue);
                            break;
                        case "float":
                        case "java.lang.Float":
                            val = Float.valueOf(fieldValue);
                            break;
                        case "byte":
                        case "java.lang.Byte":
                            val = Byte.valueOf(fieldValue);
                            break;
                        case "short":
                        case "java.lang.Short":
                            val = Short.valueOf(fieldValue);
                            break;
                    }
                    method.invoke(o,val);
                }
                beansContainer.put(id,o);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String s) throws BeansException {
        Object o = beansContainer.get(s);
        return o;
    }

    public <T> T getBean(Class<T> aClass) throws BeansException {
        Collection<Object> values = beansContainer.values();
        Iterator<Object> iterator = values.iterator();
        while (iterator.hasNext()){
            Object next = iterator.next();
            if (next.getClass().equals(aClass)) {
                return (T) next;
            }
        }
        return null;
    }
    //部分未实现功能此处省略
}

上述部分就是实现简单的IOC重点内容。主要是基于 XML解析和发射知识。

项目测试

项目测试代码

ApplicationContext context = new MyApplicationContext("spring.xml");
User o = context.getBean(User.class);
System.out.println(JSONObject.toJSONString(o));

测试结果

{
    "age": 2,
    "ageB": 20,
    "buy": 10.05,
    "buyD": 100.5,
    "height": 170,
    "heightS": 1700,
    "id": 1,
    "idI": 10,
    "name": "欧阳",
    "salary": 7500.5,
    "salaryF": 9000.5,
    "sex": "m",
    "sexC": "f",
    "success": false,
    "successB": true,
    "weight": 60,
    "weightL": 600
}

注意:这里只是实现了一个简单的IOC容器,并且只是实现了 java的简单类型和 包装类型,以及String类型的注入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值