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…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
虚幻基础:角色旋转
能帮到你的话,就给个赞吧 😘 文章目录 移动组件使用控制器所需旋转:组件 使用 控制器旋转将旋转朝向运动:组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转:必须移动才能旋转,不移动不旋转控制器…...
算法刷题-回溯
今天给大家分享的还是一道关于dfs回溯的问题,对于这类问题大家还是要多刷和总结,总体难度还是偏大。 对于回溯问题有几个关键点: 1.首先对于这类回溯可以节点可以随机选择的问题,要做mian函数中循环调用dfs(i&#x…...