自己动手写一个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容器?

相关推荐
苍何4 小时前
Coding 真有质的飞跃?实测下豆包seed 2.1 pro
后端
苍何4 小时前
试了下腾讯 Marvis,回不去了...
后端
caibixyy4 小时前
springboot+langchain4j 实战 Day14——工具嵌入多 Agent(Tool-Equipped Multi-Agent)
后端
caibixyy4 小时前
springboot+langchain4j 实战 Day13 多 Agent 协作(Router + 子 Agent 分流)
后端
飘尘5 小时前
前端转全栈(Java 后端)必须要知道的:开发中的锁机制与分布式并发控制
前端·后端·全栈
苍何5 小时前
清华团队做了个具身智能大脑,有点东西!
后端
fliter5 小时前
强类型的诅咒,还是 Rust 类型系统的生存指南
后端
用户8356290780515 小时前
Python 操作 PDF 附件:添加、查看与管理指南
后端·python