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

相关推荐
garmin Chen1 小时前
Prompt工程入门:让AI按你的要求工作(1)--prompt概述与设计
java·人工智能·python·junit·prompt·agent
江湖中的阿龙1 小时前
Go语言零基础入门教程(一)环境搭建与基础入门
开发语言·后端·golang
集成显卡9 小时前
Rust实战七 |基于带 colored 颜色文字控制台的批量文件删除工具
开发语言·后端·rust
刀法如飞10 小时前
AI时代:DDD领域驱动建模与Ontology语义建模的区别
java·设计模式·架构
jeffer_liu10 小时前
Spring AI 生产级实战:工具调用
java·人工智能·后端·spring·ai编程
比昨天多敲两行10 小时前
linux 线程概念与控制
java·开发语言·jvm
8Qi810 小时前
LeetCode 75:颜色分类(荷兰国旗问题)—— Java 题解 ✅
java·算法·leetcode·指针·排序
zzhongcy11 小时前
@Transactional 同类内部调用失效 + 两种自代理解决方案
java