Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架

简单手写SpringIOC框架

    • 环境搭建
      • 基于XML方式
        • 项目结构
        • 项目代码
        • 运行结果
      • 基于注解方式
        • 项目结构
        • 项目代码
        • 运行结果
    • 简单手写SpringIOC框架
      • 核心原理
      • 基于XML方式
        • 原理
        • 项目结构
        • 项目代码
        • 运行结果
      • 基于注解方式
        • 原理
        • 项目结构
        • 项目代码
        • 运行结果

环境搭建

基于XML方式

项目结构

在这里插入图片描述

项目代码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
    </dependencies>

</project>

UserBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-08 14:58:16
 */
public class UserBean {
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userBean" class="com.spring.bean.UserBean"/>

</beans>

SpringTest01.java

package com.spring.test;

import com.spring.bean.UserBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author honey
 * @date 2023-08-08 14:59:56
 */
public class SpringTest01 {

    public static void main(String[] args) {
        // 读取spring.xml
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        // 从IOC容器中读取对象
        UserBean userBean = applicationContext.getBean("userBean", UserBean.class);
        System.out.println(userBean);
    }
}

运行结果

在这里插入图片描述

基于注解方式

项目结构

在这里插入图片描述

项目代码

ScanBean.java

package com.spring.bean.scan;

import org.springframework.stereotype.Component;

/**
 * @author honey
 * @date 2023-08-08 16:37:26
 */
@Component
public class ScanBean {
}

SpringConfig.java

package com.spring.config;

import com.spring.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author honey
 * @date 2023-08-08 16:30:21
 */
@Configuration
@ComponentScan(value = {"com.spring.bean.scan"})
public class SpringConfig {

    @Bean(name = "user")
    public UserBean userBean() {
        return new UserBean();
    }
}

SpringTest02.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.bean.scan.ScanBean;
import com.spring.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author honey
 * @date 2023-08-08 16:31:25
 */
public class SpringTest02 {

    public static void main(String[] args) {
        // 加载SpringConfig
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 从IOC容器中读取对象
        UserBean userBean = applicationContext.getBean("user", UserBean.class);
        System.out.println(userBean);
        ScanBean scanBean = applicationContext.getBean("scanBean", ScanBean.class);
        System.out.println(scanBean);
    }
}

运行结果

在这里插入图片描述

简单手写SpringIOC框架

核心原理

底层使用map集合管理对象,key=beanId,value=实例对象

private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

基于XML方式

原理

基于反射+工厂模式+DOM技术

  1. 使用DOM技术解析spring.xml文件;
  2. 获取bean的id和class属性;
  3. 根据类的完整路径使用反射技术初始化对象;
  4. 使用工厂模式管理初始化对象;

项目结构

在这里插入图片描述

项目代码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>ext-spring-ioc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

</project>

UserBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-08 16:56:32
 */
public class UserBean {
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userBean" class="com.spring.bean.UserBean"/>

</beans>

SpringIocXml.java

package com.spring.ext;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author honey
 * @date 2023-08-08 16:57:17
 */
public class SpringIocXml {

    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

    public SpringIocXml() throws IOException, DocumentException {
        init();
    }

    public <T> T getBean(String name) {
        return (T) beanMap.get(name);
    }

    /**
     * 初始化IOC容器
     */
    private void init() throws IOException, DocumentException {
        // 解析spring.xml配置
        ClassPathResource classPathResource = new ClassPathResource("spring.xml");
        File xmlFile = classPathResource.getFile();
        SAXReader saxReader = new SAXReader();
        Document doc = saxReader.read(xmlFile);
        // 获取根节点
        Element rootElement = doc.getRootElement();
        // 获取bean节点信息
        List<Element> beans = rootElement.elements("bean");
        for (Element bean : beans) {
            try {
                String beanId = bean.attribute("id").getValue();
                String classPath = bean.attribute("class").getValue();
                // 使用反射机制初始化对象,并将对象存入Map集合
                Class<?> clazz = Class.forName(classPath);
                Object object = clazz.newInstance();
                beanMap.put(beanId, object);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

SpringTest01.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.ext.SpringIocXml;
import org.dom4j.DocumentException;

import java.io.IOException;

/**
 * @author honey
 * @date 2023-08-08 17:04:35
 */
public class SpringTest01 {

    public static void main(String[] args) throws DocumentException, IOException {
        SpringIocXml springIocXml = new SpringIocXml();
        UserBean userBean = springIocXml.getBean("userBean");
        System.out.println(userBean);
    }
}

运行结果

在这里插入图片描述

基于注解方式

原理

基于反射+工厂模式实现

  1. 判断配置类上是否有@Configuration注解;
  2. 获取配置类中的所有方法,判断方法上是否有@Bean注解,如果有则获取方法的返回值作为实例对象;
  3. 判断配置类上是否有@ComponentScan注解,如果有则扫描指定包下的所有类,并判断类上是否有@Component注解,如果有则通过反射技术初始化对象;
  4. 使用工厂模式管理初始化对象/实例对象;

项目结构

在这里插入图片描述

项目代码

pom.xml

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.7</version>
</dependency>

ScanBean.java

package com.spring.bean.scan;

import org.springframework.stereotype.Component;

/**
 * @author honey
 * @date 2023-08-09 14:28:33
 */
@Component
public class ScanBean {
}

SpringConfig.java

package com.spring.config;

import com.spring.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author honey
 * @date 2023-08-09 14:26:40
 */
@Configuration
@ComponentScan(value = {"com.spring.bean.scan"})
public class SpringConfig {

    @Bean
    public UserBean userBean() {
        return new UserBean();
    }
}

SpringIocAnnotation.java

package com.spring.ext;

import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.StrUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author honey
 * @date 2023-08-09 14:12:21
 */
public class SpringIocAnnotation {

    private final Object config;
    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

    public SpringIocAnnotation(Object config) {
        this.config = config;
        init();
    }

    /**
     * 初始化IOC容器
     */
    public void init() {
        // 判断配置类上是否有@Configuration注解
        Configuration configuration = this.config.getClass().getDeclaredAnnotation(Configuration.class);
        if (configuration == null) {
            return;
        }

        // 处理@Bean注解
        Class<?> clazz = config.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // 判断方法上是否有@Bean注解
            Bean bean = method.getDeclaredAnnotation(Bean.class);
            if (bean != null) {
                try {
                    // 获取beanId
                    String[] value = bean.value();
                    String beanId = value.length > 0 ? value[0] : method.getName();
                    // 获取方法的返回值
                    Object object = method.invoke(config);
                    beanMap.put(beanId, object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // 处理@Component注解
        ComponentScan componentScan = clazz.getDeclaredAnnotation(ComponentScan.class);
        if (componentScan != null) {
            for (String packageName : componentScan.value()) {
                try {
                    // 扫描指定包下的所有类
                    Set<Class<?>> classes = ClassScanner.scanPackage(packageName);
                    for (Class<?> c : classes) {
                        // 判断类上是否有@Component注解
                        Annotation component = c.getDeclaredAnnotation(Component.class);
                        if (component != null) {
                            try {
                                // 获取beanId
                                String beanId = StrUtil.lowerFirst(c.getSimpleName());
                                // 通过反射技术初始化对象
                                Object beanObject = c.newInstance();
                                beanMap.put(beanId, beanObject);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public <T> T getBean(String name) {
        return (T) beanMap.get(name);
    }
}

SpringTest02.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.bean.scan.ScanBean;
import com.spring.config.SpringConfig;
import com.spring.ext.SpringIocAnnotation;

/**
 * @author honey
 * @date 2023-08-09 14:24:36
 */
public class SpringTest02 {

    public static void main(String[] args) {
        SpringIocAnnotation springIocAnnotation = new SpringIocAnnotation(new SpringConfig());
        UserBean userBean = springIocAnnotation.getBean("userBean");
        System.out.println(userBean);
        ScanBean scanBean = springIocAnnotation.getBean("scanBean");
        System.out.println(scanBean);
    }
}

运行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/74057.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【量化课程】08_1.机器学习量化策略基础实战

文章目录 1. 常用机器学习模型1.1 回归模型1.2 分类模型1.2.1 SVC介绍1.2.2 SVC在量化策略中的应用 2. 机器学习量化策略实现的基本步骤3. 策略实现 1. 常用机器学习模型 1.1 回归模型 线性回归多层感知器回归自适应提升树回归随机森林回归 1.2 分类模型 线性分类支持向量机…

excel 下载方法封装

1.首先需要拿到后端返回的URL下载地址 2.写个下载方法 // url 接口返回的下载地址。例如&#xff1a;https://cancer-research.oss-cn-beijing.aliyuncs.com/yuance-platform-permission/校内共享数据导入模板.xlsx // name 文件名称 例如&#xff1a; 校内共享数据导入模板 /…

反编译微信小程序,可导出uniapp或taro项目

微信小程序反编译&#xff08;全网通用&#xff09; 微信小程序反编译 反编译主要分为四个阶段 操作流程 1. node.js安装 2. node安装模块 3. 开始反编译 4. 导入到微信开发者工具既可运行 微信小程序反编译 当碰到不会写的小程序功能时&#xff0c;正好看到隔壁小程序有类似…

Android学习之路(3) 布局

线性布局LinearLayout 前几个小节的例程中&#xff0c;XML文件用到了LinearLayout布局&#xff0c;它的学名为线性布局。顾名思义&#xff0c;线性布局 像是用一根线把它的内部视图串起来&#xff0c;故而内部视图之间的排列顺序是固定的&#xff0c;要么从左到右排列&#xf…

前后端分离------后端创建笔记(03)前后端对接(下)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

Java【数据结构】二分查找

&#x1f31e; 题目&#xff1a; &#x1f30f;在有序数组A中&#xff0c;查找目标值target &#x1f30f;如果找到返回索引 &#x1f30f;如果找不到返回-1 算法描述解释前提给定一个内含n个元素的有序数组A&#xff0c;满足A0<A1<A2<<An-1,一个待查值target1设…

游戏中的UI适配

引用参考&#xff1a;感谢GPT UI适配原理以及常用方案 游戏UI适配是确保游戏界面在不同设备上以不同的分辨率、屏幕比例和方向下正常显示的关键任务。下面是一些常见的游戏UI适配方案&#xff1a; 1.分辨率无关像素&#xff08;Resolution-Independent Pixels&#xff09;&a…

【EI/SCOPUS检索】第三届计算机视觉、应用与算法国际学术会议(CVAA 2023)

第三届计算机视觉、应用与算法国际学术会议&#xff08;CVAA 2023) The 3rd International Conference on Computer Vision, Application and Algorithm 2023年第三届计算机视觉、应用与算法国际学术会议&#xff08;CVAA 2023&#xff09;主要围绕计算机视觉、计算机应用、计…

Python程序设计基础:函数(二)

文章目录 一、lambda()函数二、递归函数三、变量的作用域 一、lambda()函数 lambda()函数是一种简便的&#xff0c;将函数定义在同一行的函数方法。lambda()实际上生成了一个函数对象&#xff08;匿名函数&#xff09;&#xff0c;它主要用于需要函数对象作为参数或函数比较简…

ChatGPT能代替搜索引擎吗?ChatGPT和搜索引擎有什么区别?

ChatGPT和搜索引擎是两种在信息获取和交流中常用的工具&#xff0c;ChatGPT是一种基于人工智能技术的聊天机器人&#xff0c;而搜索引擎是一种在互联网上搜索信息的工具。尽管它们都是依托互联网与信息获取和交流有关&#xff0c;部分功能重合&#xff0c;但在很多方面存在着明…

并发编程 - 线程池中的常见面试题

目录 1. 线程池相比于线程有什么优点 2. 线程池的参数有哪些 3. 线程工厂有什么用 4. 说一下线程的优先级 5. 说一下线程池的执行流程 6. 线程池的拒绝策略有哪些 7. 如何实现自定义拒绝策略 8. 如何判断线程池中的任务是否执行完成 1. 线程池相比于线程有什么优点 有…

2023.8.14论文阅读

文章目录 ESPNet: Efficient Spatial Pyramid of Dilated Convolutions for Semantic Segmentation摘要本文方法实验结果 DeepFusion: Lidar-Camera Deep Fusion for Multi-Modal 3D Object Detection摘要本文方法实验结果 ESPNet: Efficient Spatial Pyramid of Dilated Convo…

ASR 语音识别接口封装和分析

这个文档主要是介绍一下我自己封装了 6 家厂商的短语音识别和实时流语音识别接口的一个包&#xff0c;以及对这些接口的一个对比。分别是&#xff0c;阿里&#xff0c;快商通&#xff0c;百度&#xff0c;腾讯&#xff0c;科大&#xff0c;字节。 zxmfke/asrfactory (github.c…

Stable Diffusion + AnimateDiff运用

1.安装AnimateDiff&#xff0c;重启webui 2.下载对应的模型&#xff0c;最好到c站下载&#xff0c;google colab的资源有可能会出现下载问题 https://civitai.com/models/108836 3.下载完成后&#xff0c;你可以随便抽卡了。 抽卡完成后固定seed&#xff0c;然后打开这个插件&…

Docker安装elasticsearch分布式搜索

文章目录 ☀️安装elasticsearch☀️1.部署单点es&#x1f338;1.1.创建网络&#x1f338;1.2.下载镜像&#x1f338;1.3.运行 ☀️2.部署kibana&#x1f338;2.1.部署&#x1f338;2.2.DevTools ☀️3.安装IK分词器&#x1f338;3.1.在线安装ik插件&#xff08;较慢&#xff0…

【报错】ModuleNotFoundError: No module named ‘websocket‘

1 报错 ModuleNotFoundError: No module named websocket 2 解决方法 pip install websocket 1 报错 AttributeError: module websocket has no attribute enableTrace 2 分析 一般是由于websocket的依赖包没有安装造成的。websocket.enableTrace()方法是在websocket-cli…

013 怎么激活win10系统?

1、搜索软件Windows PowerShell&#xff1a; 在“开始”菜单栏&#xff0c;搜索“Windows PowerShell.exe”,以管理员模式打开。 2、输入 三条命令&#xff1a; &#xff08;1&#xff09;slmgr /ipk VK7JG-NPHTM-C10JM-9MPGT-3A77T &#xff08;最后这个字符为秘钥&#xf…

Qt自定义对话框

介绍 自定义框主要通过对现有对话框QDialog类的派生&#xff0c;根据需求编写成员函数、重载信号函数、槽函数&#xff0c;进而实现在主QWidget中点击某个按钮后&#xff0c;一个对话框的弹出 流程 简化创建派生类 最后点击完成即可。 自定义ui界面&#xff0c;编写成员函数…

drawio导出矢量图

1.选中要导出的图 2.导出为pdf 3.用adobe打开pdf&#xff0c;另存为eps