学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • 案例实践

  • 工具使用

  • 项目搭建

  • 服务治理

  • ORM框架

  • MiniSpring

    • Spring IoC-原始Ioc
      • 一、IoC容器概念
        • 1、基本概念
        • 2、组成结构
      • 二、简易IoC容器实现
        • 1、XML解析工具
        • 2、Bean定义
        • 3、解析XML构建上下文
        • 4、功能验证
      • 三、优化Ioc容器
        • 1、自定义Bean异常
        • 2、资源加载
        • 3、Bean工厂
        • 4、Bean注册
      • 参考
    • Spring IoC-扩展Bean
    • Spring IoC-属性注入
    • Spring Ioc-解决循环依赖
    • Spring Ioc-注解支持
    • Spinrg IoC-IoC完善
  • 案例归档
  • MiniSpring
旭日
2023-04-28
目录

Spring IoC-原始Ioc

# 一、IoC容器概念

# 1、基本概念

使用Bean容器去管理一个个的Bean,通过BeanFactory将创建对象与使用对象的业务代码解耦,把Bean的管理交给容器,业务开发人员无须去关心Bean的构建和生命周期管理。

# 2、组成结构

  • 一个部件去对应Bean内存的映射

  • XML reader从外部XML文件获取Bean的声明

  • 反射部件加载Bean Class并创建实例

  • 一个Map保存Bean的实例

  • 对外提供getBean()方法供外部使用

# 二、简易IoC容器实现

# 1、XML解析工具

xml文件中会去配置Bean的id和class

  • id:别名
  • class:实际加载的bean类
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id = "xxxid" class = "me.xu.xxxclass"></bean>
</beans>

我们需要引入dom4j依赖,帮助我们快速处理XML文件:

        <!--xml解析工具-->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

# 2、Bean定义

XML中我们只有两个最简单的属性id和Class,所以我们这个Bean定义类很简单:

public class BeanDefinition {
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    /**
     * Bean id
     */
    private String id;

    /**
     * Bean类名
     */
    private String className;

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

}

# 3、解析XML构建上下文

XML所对应Bean构建好之后,我们就需要去解析XML,并把解析后的内容用于构建上下文:

public class ClassPathXmlApplicationContext {

    /**
     * BeanDefinition集合
     */
    private List<BeanDefinition> beanDefinitions = new ArrayList<>();

    /**
     * Bean的单例
     */
    private Map<String, Object> singletons = new HashMap<>();

    public ClassPathXmlApplicationContext(String fileName) {
        this.readXml(fileName);
        this.instanceBeans();
    }

    /**
     * 解析XML,获取Bean实例,放入Bean集合中
     */
    private void readXml(String fileName) {
        // 创建读取对象
        SAXReader saxReader = new SAXReader();
        try {
            // XML路径获取
            URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
            Document document = saxReader.read(xmlPath);
            Element rootElement = document.getRootElement();
            // 对配置文件中每一个Bean进行处理
            for (Element element : (List<Element>) rootElement.elements()) {
                String beanID = element.attributeValue("id");
                String beanClassName = element.attributeValue("class");
                BeanDefinition beanDefinition = new BeanDefinition(beanID, beanClassName);
                beanDefinitions.add(beanDefinition);

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void instanceBeans() {
        for (BeanDefinition beanDefinition : beanDefinitions) {
            try {
                // 反射创建Bean实例放入单例中
                singletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public Object getBean(String beanName) {
        return singletons.get(beanName);
    }

}

类中两个变量:

  • beanDefinitions:用于存储BeanDefinition变量
  • singletons:Bean单例集合

类中两个方法:

  • readXml:按照一定格式读取XML文件,并获取XML文件中每个Bean的id和class,实例化对象beanDefinition,并放入集合中。
  • instanceBeans:由于beanDefinitions中存储的只是Class名,并非Bean实例,通过遍历这个集合,反射加载Bean对象,放入单例集合中。

# 4、功能验证

在SpringBoot中如果我们要注入一个Bean,通常是采用注解的方式,现在使用这个最简单的IoC容器,我们在XML文件中进行正确配置,然后进行功能验证。

服务类

public interface DemoService {
    void test();
}
public class DemoServiceImpl implements DemoService{
    @Override
    public void test() {
        System.out.println("hello mini-spring");
    }
}

XML配置

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id = "DemoService" class = "me.xu.spring.test.demo1.DemoServiceImpl"></bean>
</beans>

测试

public class Demo {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("demo.xml");
        DemoService demoService = (DemoService)classPathXmlApplicationContext.getBean("DemoService");
        demoService.test();
    }
}

# 三、优化Ioc容器

在上例的案例中,我们的ClassPathXmlApplicationContext主要负责了加载XML文件和实例化Bean对象,我们需要将这个类进行分解:

  • 最基本的核心容器
  • XML外部访问抽离出来,便于后续对其他文件比如数据库、WEB等需求进行扩展

# 1、自定义Bean异常

public class BeansException extends Exception{
    public BeansException(String msg) { super(msg); }
}

# 2、资源加载

资源定义

public interface Resource extends Iterator<Object>{

}

目前由于是从XML进行资源加载的,后续可能会从其他地方进行加载,通过这个接口方便后续的扩展。

XML资源加载

public class ClassPathXmlResource implements Resource {
    Document document;
    Element rootElement;
    Iterator<Element> elementIterator;
    public ClassPathXmlResource(String fileName) {
        SAXReader saxReader = new SAXReader();
        URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
        // 将配置文件装载进来,生成一个迭代器,可以用于遍历
        try {
            this.document = saxReader.read(xmlPath);
            this.rootElement = document.getRootElement();
            this.elementIterator = this.rootElement.elementIterator();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
    public boolean hasNext() {
        return this.elementIterator.hasNext();
    }
    public Object next() {
        return this.elementIterator.next();
    }
}

# 3、Bean工厂

Bean工厂接口

public interface BeanFactory {

    /**
     * 根据Bean名称,获取Bean对象
     *
     * @param beanName Bean名称
     * @return Bean对象
     * @throws BeansException Bean自定义异常
     */
    Object getBean(String beanName) throws BeansException;

    /**
     * 注册BeanDefinition
     *
     * @param beanDefinition Bean定义对象
     */
    void registerBeanDefinition(BeanDefinition beanDefinition);
}

Bean工厂具体实现

public class SimpleBeanFactory implements BeanFactory {

    /**
     * Bean定义集合
     */
    private List<BeanDefinition> beanDefinitions = new ArrayList<>();

    /**
     * Bean的id集合
     */
    private List<String> beanNames = new ArrayList<>();

    /**
     * Bean单例集合
     */
    private Map<String, Object> singletons = new HashMap<>();

    public SimpleBeanFactory() {

    }


    @Override
    public Object getBean(String beanName) throws BeansException {
        // 先尝试从单例集合中获取
        Object singleton = singletons.get(beanName);
        // 如果没有,开始实例化Bean
        if (singleton == null) {
            // 序号
            int i = beanNames.indexOf(beanName);
            if (i == -1) {
                throw new BeansException("BeanName错误");
            } else {
                // 获取Bean定义对象
                BeanDefinition beanDefinition = beanDefinitions.get(i);
                try {
                    // 反射创建Bean对象
                    singleton = Class.forName(beanDefinition.getClassName()).newInstance();
                    // 注册Bean实例
                    singletons.put(beanDefinition.getId(), singleton);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
        return singleton;
    }

    @Override
    public void registerBeanDefinition(BeanDefinition beanDefinition) {
        beanDefinitions.add(beanDefinition);
        beanNames.add(beanDefinition.getId());
    }
}

# 4、Bean注册

public class XmlBeanDefinitionReader {

    BeanFactory beanFactory;

    /**
     * 构造函数
     * @param beanFactory bean工厂
     */
    public XmlBeanDefinitionReader(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 遍历资源,将资源中的bean对象进行注册
     * @param resource 外部资源
     */
    public void loadBeanDefinitions(Resource resource) {
        while (resource.hasNext()) {
            Element element = (Element) resource.next();
            String beanID = element.attributeValue("id");
            String beanClassName = element.attributeValue("class");
            BeanDefinition beanDefinition = new BeanDefinition(beanID, beanClassName);
            beanFactory.registerBeanDefinition(beanDefinition);
        }
    }

}

# 参考

手把手带你写一个 MiniSpring (opens new window)

#Spring
上次更新: 2024/06/29, 15:13:44
ORM整合Spring
Spring IoC-扩展Bean

← ORM整合Spring Spring IoC-扩展Bean→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式