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…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
