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.xmlClassPathXmlApplicationContext 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) {// 加载SpringConfigAnnotationConfigApplicationContext 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技术
- 使用DOM技术解析spring.xml文件;
- 获取bean的id和class属性;
- 根据类的完整路径使用反射技术初始化对象;
- 使用工厂模式管理初始化对象;
项目结构

项目代码
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);}
}
运行结果

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

项目代码
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 {@Beanpublic 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 {// 获取beanIdString[] 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 {// 获取beanIdString 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);}
}
运行结果

相关文章:
Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架
简单手写SpringIOC框架 环境搭建基于XML方式项目结构项目代码运行结果 基于注解方式项目结构项目代码运行结果 简单手写SpringIOC框架核心原理基于XML方式原理项目结构项目代码运行结果 基于注解方式原理项目结构项目代码运行结果 环境搭建 基于XML方式 项目结构 项目代码 p…...
爬虫 学习HTML标签和元素的基本概念,了解网页的结构和内容
HTML(Hypertext Markup Language)是一种用于创建网页的标记语言,由一系列的标签组成。标签使用尖括号(< 和 >)包围,并且通常成对出现,一个是开始标签,一个是结束标签。 HTML文…...
mysql将id重新修改为递增
文章目录 场景解决,排序的话可以先按照一定大小改一下,然后将id字段删掉,再重新生成即可清空表数据,并将自增id改为1开始 场景 好比我有个配置表: CREATE TABLE config (id int NOT NULL AUTO_INCREMENT,config_key varchar(20) NOT NULL,config_value varchar(500) NOT NU…...
http、https笔记
目录 HTTP 基本概念状态码:get和post的区别:http 常⻅字段:http的缺点: HTTP/1.1HTTP/3HTTPSHTTPS和HTTP区别对称加密和⾮对称加密⾮对称加密 HTTP 基本概念 状态码: 1xx 中间状态,比如post的continue 20…...
飞凌嵌入式「国产」嵌入式核心板大盘点(三)——龙芯中科、赛昉科技
为了帮助各位工程师朋友详细了解飞凌嵌入式推出的“国产化”产品,小编专门开设了「国产平台大盘点专题」。上周,已经带大家盘点了飞凌嵌入式联合瑞芯微电子和全志科技两个国产处理器品牌打造的平台,今天,将继续为大家介绍龙芯和赛…...
以vue2为例,用npm开发环境在后端部署vue2项目(更推荐使用nginx部署)
因为之前一致出现的跨域问题,从而想到了这个办法,属于偏方。推荐使用nginx部署,再去解决跨域问题。 接下来聊一聊本文所使用的方法。 首先将你的前端vue项目拷贝一份到服务器,准备一个dockerfile文件,用这个进行部署首…...
docker容器监控:Cadvisor +Prometheus+Grafana的安装部署
目录 Cadvisor PrometheusGrafana的安装部署 一、安装docker: 1、安装docker-ce 2、阿里云镜像加速器 3、下载组件镜像 4、创建自定义网络 二、部署Cadvisor 1、被监控主机上部署Cadvisor容器 2、访问cAdvisor页面 三、安装prometheus 1、部署Prometheus…...
前端食堂技术周刊第 93 期:7 月登陆 Web 平台的新功能、Node.js 工具箱、Nuxt3 开发技巧、MF 重构方案
美味值:🌟🌟🌟🌟🌟 口味:橙橙冰萃美式 食堂技术周刊仓库地址:https://github.com/Geekhyt/weekly 大家好,我是童欧巴。欢迎来到前端食堂技术周刊,我们先来…...
获取 Android 的 SHA1 值
1、调试版,可以直接在 Android studio 中的 gradle 中查看。也可以用下面方法进行 前提要先确定签名文件所在的路径:调试版默认使用的签名文件是debug.keystore,文件处于 C 盘用户目录下的.android文件夹下。打开命令行工具, 1、…...
! [remote rejected] develop -> develop (pre-receive hook declined)
问题 git push 远程提交dao develop 分支失败,出现下面错误信息 remote: GitLab: You are not allowed to push code to protected branches on this project. To https://xxx.com.cn/xxx/xxx/xxx/xxx.git/! [remote rejected] develop -> develop (pre-receiv…...
最强的表格组件—AG Grid使用以及License Key Crack
PS: 想要官方 License Key翻到最后面 Ag Grid简介 Ag-Grid 是一个高级数据网格,适用于JavaScript/TypeScript应用程序,可以使用React、Angular和Vue等流行框架进行集成。它是一种功能强大、灵活且具有高度可定制性的表格解决方案,提供了丰富…...
【算法】逆波兰表达式
文章目录 定义求法代码思想: 定义 逆波兰表达式也称为“后缀表达式”,是将运算符写在操作数之后的运算式。 求法 *如:(ab)c-(ab)/e的转换过程: 先加上所有的括号。 (((ab)*c)-((ab)/e))将所有的运算符移到括号外面 (((ab) c)* …...
添加SQLCipher 到项目中
文章目录 一、克隆下载SQLCipher二、手动导入1. 生成sqlite3.c2. 在项目中添加命令3. 添加 Security.framework 三、CocoaPods导入 SQLCipher官方地址 一、克隆下载SQLCipher $ cd ~/Documents/code $ git clone https://github.com/sqlcipher/sqlcipher.git二、手动导入 1.…...
轻松预约,尽享美食,详解餐厅预约小程序的设计与实现
随着智能手机的普及和人们生活水平的提高,餐厅预约已经成为人们日常生活中的一部分。为了更好地满足人们的需求,许多餐厅开始使用小程序来提供更方便快捷的预约服务。本文将介绍如何制作一款餐厅预约小程序的详细步骤。 1. 进入乔拓云网后台,…...
数据结构--栈和队列3.1(栈-顺序结构)
目录 栈(Stack)栈顶(top)栈底(bottom)空栈(不含任何元素) 创建栈 入栈操作 出栈操作 销毁一个栈 计算栈的当前容量 实例分析 栈的插入操作叫做进栈(Push…...
pdf怎么压缩到1m?这样做压缩率高!
PDF是目前使用率比较高的一种文档格式,因为它具有很高的安全性,还易于传输等,但有时候当文件体积过大时,会给我们带来不便,这时候简单的解决方法就是将其压缩变小。 想要将PDF文件压缩到1M,也要根据具体的情…...
AttentionFreeTransformer 源码解析(一):AFTFull、AFTSimple、AFTLocal
我觉得源码写的很好懂,我就不加注释了,直接上计算流程图。 AFTFull class AFTFull(nn.Module):def __init__(self, max_seqlen, dim, hidden_dim64):super().__init__()max_seqlen: the maximum number of timesteps (sequence length) to be fed indim…...
C++ 计算 拟合优度R^2
解决的问题: 拟合优度(Goodness of Fit)是指回归直线对观测值的拟合程度,度量拟合优度的统计量是可决系数(亦称确定系数) R?。R最大值为 1。R%的值越接近1,说明回归直线对观测值的拟合程度越好,反之,R%值越小&#x…...
Springboot-Retrofit HTTP工具框架快速使用
在SpringBoot项目直接使用okhttp、httpClient或者RestTemplate发起HTTP请求,既繁琐又不方便统一管理。 因此,在这里推荐一个适用于SpringBoot项目的轻量级HTTP客户端框架retrofit-spring-boot-starter,使用非常简单方便,同时又提供…...
微信小程序实现人脸识别(从一个没有开通人脸核身的小程序跳转到要给开通人脸核身的小程序,进行人脸识别后再跳转回来)
A小程序没有开通人脸识别功能,B小程序开通了人脸识别。 总体思路是:从A小程序需要进行人脸识别的地方携带参数跳转到B小程序进行人脸识别,识别后把参数传递回来。 A小程序的参考代码如下: //人脸识别相关 start powerDrawerFace(e){var that = thisthat.setData({faceO…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
