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

相关推荐
郑州光合科技余经理15 小时前
代驾系统架构拆解:订单链路、权限组织与私有化源码交付
开发语言·后端·算法·架构·系统架构·uni-app·php
hboot18 小时前
AI工程师第六课 - RAG检索增强生成
后端·langchain·llm
mldong18 小时前
jeeflow:98KB 的工作流引擎长什么样
后端
Pluchon19 小时前
Java个人综合项目——萌部落社区V2.0
java·python·spring·spring cloud·postman·idea
梦雨生生20 小时前
java开发工具(学习第一天)
java·开发语言·学习
她说可以呀21 小时前
Spring-ai-alibaba文生图
java·人工智能·spring
程序员cxuan21 小时前
速度太快了!本地可以跑 DeepSeek-V4-Flash 了
人工智能·后端·程序员
阿祖zu1 天前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
松仔log1 天前
Java中级——组合和继承
android·java·开发语言
不才不才不不才1 天前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring