自己动手写一个spring之IOC_1

写在前面

本文看下如何定义IOC部分内容。

源码 。

1:基础实现

先来定义要通过ioc管理的bean,如下:

java 复制代码
public class AServiceImpl implements AService {
    public void sayHello() {
        System.out.println("a service 1 say hello");
    } 
}

为了实现IOC,我们需要先来定义一个xml文件,来表达bean信息,如下:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id = "aservice" class = "com.hc.minispring.ioc.one.v1.test.AServiceImpl"></bean>
</beans>

定义对应xml的bean定义类,beandefinition:

java 复制代码
package com.hc.minispring.ioc.one.v1;

import lombok.Data;

/**
 * bean外部定义的内存映射类
 */
@Data
public class BeanDefinition {
    private String id;
    private String className;

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

接着定义一个类来读取xml信息,并创建bean信息:

java 复制代码
public class ClassPathXmlApplicationContext {
    private List<BeanDefinition> beanDefinitions = new ArrayList<>();
    private Map<String, Object> singletons = new HashMap<>();
    //构造器获取外部配置,解析出Bean的定义,形成内存映像
    public ClassPathXmlApplicationContext(String fileName) {
        this.readXml(fileName);
        this.instanceBeans();
    }
    private void readXml(String fileName) {
        // ... 具体参看源码
    }
    //利用反射创建Bean实例,并存储在singletons中
    private void instanceBeans() {
        for (BeanDefinition beanDefinition : beanDefinitions) {
            // ... 具体参看源码
        } 
    }
    //这是对外的一个方法,让外部程序从容器中获取Bean实例,会逐步演化成核心方法
    public Object getBean(String beanName) {
        return singletons.get(beanName);
    }
}

接着我们来写一个测试类:

java 复制代码
public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("v1/beans.xml");
        AService aService = (AService)ctx.getBean("aservice");
        aService.sayHello();
    }

运行:

复制代码
a service 1 say hello

Process finished with exit code 0

2:根据单一职责改造

面向对象设计原则中的单一原则是一个很重要的原则,它不会让一个类的职责过于繁重,从而让类变得复杂,最终让整体的程序变得维护成本和扩展的成本很高,所以我们接下来对ClassPathXmlApplicationContext进行一番改造。首先对于xml这类定义bean定义的信息,我们将其抽象为资源,而数据是核心,所以我们可以定义core包来放这部分内容,定义Resource接口来代表资源:

java 复制代码
/**
 * 基础资源对应的接口,如xml,注解类等
 */
public interface Resource extends Iterator<Object>{

}

接着我们定义beans目录,放bean相关的内容,如beandifinitionreader(读取resource为bean定义),beandefinition(bean定义),beanfactory(bean的工厂),这样通过beandifinitionreader读取resource为beandifinition,然后通过beanfacotry读取beandifinition信息,创建并维护bean信息。最后在定义一个context目录,来作为整合的入口,使用上述的这些独立的功能完成bean信息的维护,定义类ClassPathXmlApplicationContext:

java 复制代码
/**
 * 集大成者的类,暴漏给用户使用
 */
public class ClassPathXmlApplicationContext implements BeanFactory {
    BeanFactory beanFactory;

    public ClassPathXmlApplicationContext(String fileName) {
        Resource res = new ClassPathXmlResource(fileName);
        BeanFactory bf = new SimpleBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
        reader.loadBeanDefinitions(res);
        this.beanFactory = bf;
    }

    @Override
    public Object getBean(String beanName) throws NoSuchBeanDefinitionException {
        return this.beanFactory.getBean(beanName);
    }

    @Override
    public void registerBeanDefinition(BeanDefinition bd) {
        this.beanFactory.registerBeanDefinition(bd);

    }
}

最终如下:

测试:

java 复制代码
public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("v2/beans.xml");
        AService aService = (AService)ctx.getBean("aservice");
        aService.sayHello();
    } 
} 

运行:

复制代码
a service 1 say hello v2

Process finished with exit code 0

这样我们就按照单一职责将不同的功能使用不同的类实现,并且将一类功能按照包的方式组织在了一起,大概如下:

复制代码
core包:
    资源相关
beans包:
    bean处理相关
context包:
    用户入口,统筹

写在后面

参考文章列表

01|原始IoC:如何通过BeanFactory实现原始版本的IoC容器? 。

相关推荐
源码集结号20 分钟前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
努力的小雨31 分钟前
给 AI 眼镜开发应用有多难?我从零做了一个陪练,还上架了
后端
论文复现现场42 分钟前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
啃瓜子的松鼠1 小时前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David2 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
excel2 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端
外收内放2 小时前
Python基础语法练习题(73)
java·前端·python
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友
用户3721574261352 小时前
Java 操作 Word 脚注和尾注:添加、读取与删除
java
AI入职记2 小时前
AI 代码审查召回率实测:20 个骗过单元测试的变异体,抓到 13 个
后端