如何手写一个SpringBoot框架
你好,我是柳岸花开。
在这篇文章中,我们将手写模拟SpringBoot的核心流程,让大家能够以一种简单的方式了解SpringBoot的大概工作原理。
项目结构
我们创建一个工程,包含两个模块:
-
springboot
模块,表示SpringBoot框架的源码实现。 -
user
包,表示用户业务系统,用来写业务代码来测试我们所模拟出来的SpringBoot。
首先,在springboot
模块中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.60</version>
</dependency>
</dependencies>
在user
模块下,我们进行正常的开发,比如先添加SpringBoot依赖,然后定义相关的Controller
和Service
:
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
定义UserController和UserService
在user
包下定义UserController
和UserService
,希望能通过运行MyApplication
中的main
方法,直接启动项目,并能在浏览器中正常访问到UserController
中的某个方法。
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("test")
public String test(){
return userService.test();
}
}
核心注解和核心类:
-
@SpringBootApplication
:这个注解加在应用启动类上,即main
方法所在的类。 -
SpringApplication
:这个类中有个run()
方法,用来启动SpringBoot应用。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
public @interface BobSpringBootApplication {
}
public class BobSpringApplication {
public static void run(Class clazz){
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(clazz);
applicationContext.refresh();
startTomcat(applicationContext);
}
private static void startTomcat(WebApplicationContext applicationContext) {
Tomcat tomcat = new Tomcat();
Server server = tomcat.getServer();
Service service = server.findService("Tomcat");
Connector connector = new Connector();
connector.setPort(8081);
Engine engine = new StandardEngine();
engine.setDefaultHost("localhost");
Host host = new StandardHost();
host.setName("localhost");
String contextPath = "";
Context context = new StandardContext();
context.setPath(contextPath);
context.addLifecycleListener(new Tomcat.FixContextListener());
host.addChild(context);
engine.addChild(host);
service.setContainer(engine);
service.addConnector(connector);
Tomcat.addServlet(context, "dispatcher", new DispatcherServlet(applicationContext));
context.addServletMappingDecoded("/", "dispatcher");
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
tomcat.getServer().await();
}
}
@BobSpringBootApplication
public class MyApplication {
public static void main(String[] args) {
BobSpringApplication.run(MyApplication.class);
}
}
实现Tomcat和Jetty的切换
如果项目中有Tomcat的依赖,那就启动Tomcat;如果有Jetty的依赖就启动Jetty;如果两者都没有则报错;如果两者都有也报错。
public interface WebServer {
void start();
}
public class TomcatWebServer implements WebServer {
@Override
public void start() {
System.out.println("启动Tomcat");
}
}
public class JettyWebServer implements WebServer {
@Override
public void start() {
System.out.println("启动Jetty");
}
}
模拟实现条件注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(BobOnClassCondition.class)
public @interface BobConditionalOnClass {
String value() default "";
}
public class BobOnClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(BobConditionalOnClass.class.getName());
String className = (String) annotationAttributes.get("value");
try {
context.getClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
模拟实现自动配置类:
@Configuration
public class WebServiceAutoConfiguration {
@Bean
@BobConditionalOnClass("org.apache.catalina.startup.Tomcat")
public TomcatWebServer tomcatWebServer() {
return new TomcatWebServer();
}
@Bean
@BobConditionalOnClass("org.eclipse.jetty.server.Server")
public JettyWebServer jettyWebServer() {
return new JettyWebServer();
}
}
在BobSpringApplication
中添加获取WebServer
的方法:
public static WebServer getWebServer(ApplicationContext applicationContext) {
Map<String, WebServer> webServers = applicationContext.getBeansOfType(WebServer.class);
if (webServers.isEmpty()) {
throw new NullPointerException();
}
if (webServers.size() > 1) {
throw new IllegalStateException();
}
return webServers.values().stream().findFirst().get();
}
通过以上步骤,我们实现了一个简单的SpringBoot,并且可以根据依赖切换Tomcat和Jetty。
👇关注我,下期了解👇 SpringBoot自动配置 回复 222,获取Java面试题合集 关于我 一枚爱折腾的Java程序猿,专注Spring干货。把路上的问题记录下来,帮助那些和我一样的人。 好奇心强,喜欢并深入研究古天文。 崇尚 个人系统创建,做一些时间越长越有价值的事情。思考 把时间留下来 又 每刻都是新的。
本文由 mdnice 多平台发布
相关文章:
如何手写一个SpringBoot框架
你好,我是柳岸花开。 在这篇文章中,我们将手写模拟SpringBoot的核心流程,让大家能够以一种简单的方式了解SpringBoot的大概工作原理。 项目结构 我们创建一个工程,包含两个模块: springboot模块,表示Spring…...
vite解决前端跨域步骤
Vite 解决跨域问题的原理主要是通过其内置的开发服务器功能实现的,具体来说,是通过 HTTP 代理(HTTP Proxy)机制。在开发环境中,Vite 服务器可以配置为一个代理服务器,将前端应用发出的请求转发到实际的后端…...
同步交互与异步交互:深入解析与选择
同步交互与异步交互:深入解析与选择 1、同步交互2、异步交互3、选择策略 💖The Begin💖点点关注,收藏不迷路💖 在软件开发的世界里,交互方式主要分为两大类:同步与异步。下面是对这两种方式的解…...
Day1
首先,大概学习了一下用anaconda去创建一个环境(因为Django是有python版本的要求),然后学着去切换环境。 创建环境:conda create -n django_study python3.10 激活环境:conda activate django_study 删除环…...
Introduction to Data Analysis with PySpark
1.DataFrame and RDDs 2.Spark Architecture 3. Data Formats and Data Sources 倘若您觉得我写的好,那么请您动动你的小手粉一下我,你的小小鼓励会带来更大的动力。Thanks....
基于双PI控制器结构的六步逆变器供电无刷直流电机调速simulink仿真
目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 无刷直流电机(BLDCM)原理 4.2 六步换相逆变器 4.3 双PI控制器设计 5.完整工程文件 1.课题概述 基于双PI控制器结构的六步逆变器供电无刷直流电机调速simulink仿真。双PI控制…...
双向链表的基本操作
#include<iostream> #include<cmath> #include<cstring> using namespace std; typedef long long ll; typedef struct line {int data;struct line *pre;//前指针struct line *next;//后指针 }line,*a; line* init_line(line*head) {cout<<"请输…...
modbus tcp和modbusRTU的区别是什么?
Modbus是一种应用广泛的通信协议,主要用于工业自动化和过程控制系统。Modbus有多种变体,其中Modbus TCP和Modbus RTU是最常见的两种。以下是它们之间的主要区别: 1. 基本定义 Modbus RTU (Remote Terminal Unit): 是基于串行通信的协议&am…...
web小游戏开发:拼图(四)对调和移动拼图玩法的实现
web小游戏开发:拼图(四)对调和移动拼图玩法的实现 对调方式对调模式实现移动方式移动的实现小结对调方式 在完成了原始拼图玩法后,剩下两个玩法其实相对就变得简单的多了。 对调模式,简单来说,就是选中两个图块,然后位置对调一下。 那么,我们来整理一下,看看需要哪…...
前端:Vue学习 - 智慧商城项目
前端:Vue学习 - 智慧商城项目 1. vue组件库 > vant-ui2. postcss插件 > vw 适配3. 路由配置4. 登录页面静态布局4.1 封装axios实例访问验证码接口4.2 vant 组件 > 轻提示4.3 短信验证倒计时4.4 登录功能4.5 响应拦截器 > 统一处理错误4.6 登录权证信息存…...
KVM调整虚拟机与CPU铆钉(绑定)关系
虚拟机铆钉CPU 把虚拟机的vCPU绑定在物理CPU上,即VCPU只在绑定的物理CPU上调度,在特定场景下达到提升虚拟机性能的目的。比如在NUMAQ系统中,把vCPU绑定在同一个NUMA节点上,可以避免CPU跨节点访问内存,避免影响虚拟机运…...
华火电焰灶:烹饪新宠,温暖与美味的完美融合
在众多厨房电器中,华火电焰灶以其独特的魅力和卓越的性能脱颖而出,成为了众多家庭的烹饪新宠。今天,就让我们一同走进华火电焰灶的精彩世界,探索它的非凡之处。 华火电焰灶,首先吸引人的便是其创新的等离子电生明火技术…...
理想发周榜,不是新能源市场的原罪
余华在他的小说《在细雨中呼喊》曾写过这么一段话: “仓廪实而知礼节,衣食足而知荣辱”,在物质需求得到满足以前,精神文明的发展难免会有所滞后。所以,贫穷,不是原罪。 同样的,在如今的新能源…...
AHK是让任何软件都支持 Shift + 鼠标滚轮 实现界面水平滚动
目录 基本介绍 详细特点 图解安装 下载失败?缓慢? 创建并运行脚本代码😃 新建空 xxx.ahk文件 vscode/记事本等编辑工具打开 复制并粘贴简易脚本 运行 其他问题 问题一:弹出无法执行此脚本 关闭脚本 基本介绍 AutoHot…...
如何在C语言中实现求解超级丑数
超级丑数是一个正整数,并且它的质因数只包含在给定的质数列表中。超级丑数的定义类似于丑数,但可以根据特定需求改变质因数的范围。下面是如何在C语言中实现求解超级丑数的代码。 我们使用最小堆(优先队列)来高效地生成超级丑数序…...
secExample靶场之java反序列化漏洞复现
我是使用kali虚拟机搭建的靶场,具体搭建步骤可以看我之前的博客内容。 访问靶机地址,打开java反序列化的 点进去后是如图的页面,随便输入一信息。 可以看到敏感信息直接显示在了页面上。 访问192.168.189.141:8080/cors1,可以看到…...
解决升级Linux内核后,open files设置无效的问题。
问题过程 操作系统是OpenEuler 20.03,内核由4.19.90-2112.8.0.0131.oe1.aarch64升级到kernel-4.19.90-2401.1.0.0233.oe1.aarch64后,重启系统后,重新开起来运行OceanBase就运行不起来了,提示open files must not be less than 20…...
关于防范勒索病毒Play新变种的风险提示
近日,工业信息化部网络安全威胁和漏洞信息共享平台监测发现针对 Linux的勒索病毒Play新变种,攻击对象主要为VMware ESXi 虚拟化环境,攻击目标包括制造、建筑业、IT、金融和房地产等行业。 Play勒索病毒又名 Balloonfly和PlayCrypt࿰…...
一款.NET开源、跨平台的DASH/HLS/MSS下载工具
前言 今天大姚给大家分享一款.NET开源(MIT License)、免费、跨平台的DASH/HLS/MSS下载工具,并且支持点播和直播(DASH/HLS)的内容下载:N_m3u8DL-RE。 网络流媒体传输协议介绍 DASH DASH是一种基于HTTP的…...
MATLAB学习日志DAY21
结构体(2) 如果将生成逗号分隔列表的表达式括在方括号中,MATLAB 会将该列表中的每一项都存储在数组中。示例中,MATLAB 创建一个数值行向量,该向量包含结构体数组 S 的每个元素的 score 字段: scores [S.…...
Spingboot请求tcp 方式
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel;/*** 请求tcp接口** author Mr丶s* date 2024/7/1…...
leetcode刷题日记-括号生成
题目描述 题目解析 回溯的题目,不过这个两个if我就感觉有点难以理解了,不过仔细的思考了一下,确实考虑到了每个位置的情况,特别是针对右边括号 题目代码 class Solution:def generateParenthesis(self, n: int) -> List[str…...
小程序按钮分享
使用button设置: open-type"share":来微信分享; html: <button open-type"share"></button>...
多模态多智能体,在实现系统2(深思熟虑)方面的探索
多模态和多智能体,在系统2(深思熟虑)方面的探索 提出背景理性的定义为什么理性定义是四大基本原则,而不是其他数量,又为何是这四个,而不是其他?理性 不等于 推理 通过多模态多智能体系统增强理性…...
【CAN通讯系列8】如何准确接收数据?
在 【CAN通讯系列7】波特率是什么?已经介绍了CAN位时间和采样点等概念,每1位由同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2)四个段组成,这个也成为位时序,采样点位置处于PBS1和PBS2的交界处,如…...
RabbitMQ知识总结(基本概念)
文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 基本概念 Producer: 消息的生产者,是一个向…...
Prel语言入门学习:一篇全面的指南
引言 在编程语言的海洋中,Prel是一个较少人知的新星。作为一种专为数据处理和分析设计的语言,Prel结合了现代编程语言的简洁性与功能性,提供了一种独特的解决方案,尤其适用于数据科学家和分析师。本文将详细介绍Prel语言的基础&am…...
在云服务器上自动化部署项目,jenkins和gitee
▮全文概述 在编写项目时,很头大的事情就是需要自己手动的上传jar包到服务器上启动。如果出现一点bug,就要重头上传和启动。这是一件很烦的事情,所以,可以使用jenkins和gitee实现项目的自动部署 ▮全流程 在本地提交代码到gitee …...
python 参数输入
在 Python 中,参数输入通常有多种方式,这取决于你要从何处获取参数。以下是几种常见的方法: 1. 命令行参数 使用 sys.argv 获取命令行参数,或者使用 argparse 模块进行更复杂的参数解析。 示例 1: 使用 sys.argv import sys# …...
Spring面试篇章——Spring基本概述
Spring 的基本概述 Spring学习的核心内容—一图胜千言 IOC:控制反转,可以管理 Java 对象AOP:切面编程JDBCTemplate:是Spring提供一套访问数据库的技术,应用性强,相对好理解声明式事务:基于IOC …...
网站服务器是网站的空间吗/推广网站排名
前言 Apollo是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端。本文介绍了配置的概念、配置中心的必要性以及Apollo的特点,着重拆解分析Apollo客户端的设计原理,…...
做asp动态网站制作流程/建站软件可以不通过网络建设吗
栈与队列就像一对兄弟一样,学习的时候可以一块学习。 栈的特点:先进后出 队列的特点:先进先出 一、头文件 栈的头文件 #include<stack> 队列的头文件 #include<queue> 二、定义 栈的定义:stack<TYPE> s; 队列…...
网站建设公司运营/app推广引流
java 对称加密算法实现详解发布时间:2020-08-24 14:26:05来源:脚本之家阅读:99作者:小破孩123前言对于信息的加密方式多种多样,之前为大家介绍了一种自己设计的加密方式,有兴趣的朋友可以欣赏一下ÿ…...
网站推广预算/网址最全的浏览器
ThinkPHP3.2判断是否为手机端访问并跳转到另一个模块的方法 目录结构 公共模块Common,Home模块,Mobile模块配置Application/Common/Conf/config.php文件 MODULE_ALLOW_LIST > Home,Mobile接下来配置Application/Common/Common/function.php文件 添加…...
买个域名自己做网站吗/苏州网站建设公司排名
近期看一个音频传输代码时,对方采用了LinkedBlockingQueue为生产者、消费者模式,来支撑读写线程。 个人感觉非常不错,因此也对这种方式进行总结,并梳理了一个基本的功能框架备用。主要两点: 1、当对queue采用take操作…...
公司注册后怎么做网站/seo关键词如何布局
1 引言 摘要:在这项工作中,我们旨在构建一个性能强大的简单,直接和快速的实例分割框架。我们遵循SOLOv1方法的原理。" SOLO:按位置分割对象"。重要的是,我们通过动态学习目标分割器的mask head 。具体来说&a…...