当前位置: 首页 > news >正文

手写springboot

前言

 首先确定springboot在spring基础上主要做了哪些改动:
  1. 内嵌tomcat
  2. spi技术动态加载

一、基本实现

1. 建一个工程目录结构如下:

springboot:  源码实现逻辑
user         :   业务系统

在这里插入图片描述

2.springboot工程项目构建

1. pom依赖如下

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

2. SpringBoot时,核心会用到SpringBoot一个类和注解:

  1. @SpringBootApplication,这个注解是加在应用启动类上的,也就是main方法所在的类
  2. SpringApplication,这个类中有个run()方法,用来启动SpringBoot应用的.

下面一一实现:

 @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Configuration@ComponentScan@Import(KcImportSelect.class)
public @interface KcSpringBootApplication {}
public class KcSpringApplication {public static AnnotationConfigWebApplicationContext  run(Class cls){/*** spring启动步骤:* 1、构建上下文对象* 2、注册配置类* 3、刷新容器*/AnnotationConfigWebApplicationContext  context=new AnnotationConfigWebApplicationContext();context.register(cls);context.refresh();/*** 内嵌tomcat\jetty  启动*/WebServer  webServer=getWebServer(context);webServer.start();return context;}/*** 获取服务,有可能tomcat\jetty或者其他服务器* @param context* @return*/public static WebServer getWebServer(AnnotationConfigWebApplicationContext  context){Map<String, WebServer> beansOfType = context.getBeansOfType(WebServer.class);if(beansOfType.isEmpty()||beansOfType.size()>1){throw new NullPointerException();}return beansOfType.values().stream().findFirst().get();}}
3.内嵌tomcat、jetty服务器实现

项目根据pom配置动态实现tomcat\jetty内嵌要求如下:

  1. 如果项目中有Tomcat的依赖,那就启动Tomcat
  2. 如果项目中有Jetty的依赖就启动Jetty
  3. 如果两者都没有则报错
  4. 如果两者都有也报错

首先定义服务接口WebServer

public interface WebServer {void  start()  ;
}

tomcat服务实现:

public class TomcatWebServer implements WebServer {private Tomcat tomcat;public TomcatWebServer(WebApplicationContext webApplicationContext) {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(contextPath, "dispatcher", new DispatcherServlet(webApplicationContext));context.addServletMappingDecoded("/*", "dispatcher");}@Overridepublic void start() {try {System.out.println("tomcat start......");tomcat.start();}catch (Exception e){e.printStackTrace();}}
}

jetty服务实现(具体实现逻辑没写,具体实现逻辑类似tomcat实现)

public class JettyWebServer implements WebServer{@Overridepublic void start() {System.out.println("jetty  start......");}
}

思考:jetty\tomcat都已实现,总不能用if/else这样决定用哪个服务扩展性太差,基于此,就联想到spring的Condition条件注解和参考springboot中的OnClassCondition这个注解。

具体实现如下:

public class KcOnClassCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(KcConditionalOnClass.class.getName());String value = (String) annotationAttributes.get("value");try {context.getClassLoader().loadClass(value);} catch (ClassNotFoundException e) {return false;}return true;}
}
@Configuration
public class WebServerConfiguration{@Bean@KcConditionalOnClass("org.apache.catalina.startup.Tomcat")public TomcatWebServer tomcatWebServer( WebApplicationContext webApplicationContext){return new TomcatWebServer(webApplicationContext);}@Bean@KcConditionalOnClass("org.eclipse.jetty.server.Server")public JettyWebServer  jettyWebServer(){return new JettyWebServer();}
}

至此,springboot简化版已实现完成,首先启动看看
在这里插入图片描述

4.基于JDK的SPI实现扫描AutoConfiguration接口

  • AutoConfiguration接口
public interface AutoConfiguration {
}
  • 实现DeferredImportSelector接口实现类(具体为什么实现Import这个接口,请看以前的文章,主要这个接口具有延迟功能)
public class KcImportSelect implements DeferredImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {ServiceLoader<AutoConfiguration> load = ServiceLoader.load(AutoConfiguration.class);List<String> list = new ArrayList<>();for (AutoConfiguration autoConfiguration : load) {list.add(autoConfiguration.getClass().getName());}return list.toArray(new String[0]);}
}
  • 即KcSpringBootApplication注解导入该配置类
 @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Configuration@ComponentScan@Import(KcImportSelect.class)
public @interface KcSpringBootApplication {}
  • WebServerConfiguration实现AutoConfiguration接口
@Configuration
public class WebServerConfiguration implements AutoConfiguration{@Bean@KcConditionalOnClass("org.apache.catalina.startup.Tomcat")public TomcatWebServer tomcatWebServer( WebApplicationContext webApplicationContext){return new TomcatWebServer(webApplicationContext);}@Bean@KcConditionalOnClass("org.eclipse.jetty.server.Server")public JettyWebServer  jettyWebServer(){return new JettyWebServer();}
}
  • 在springboot项目下创建META-INFO/service 接口全路径命名的文件,文件内容接口实现类全路径
    在这里插入图片描述

至此,springboot简易版已全部实现。

二、应用业务系统引入自己构建的springboot

1、user项目的pom依赖(引入自己构建的springboot项目)

    <dependencies><dependency><groupId>com.kc</groupId><artifactId>springboot</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>

2、启动类

@ComponentScan(basePackages = {"kc.*"})@KcSpringBootApplication
public class UserApplication {public static void main(String[] args) {AnnotationConfigWebApplicationContext run = KcSpringApplication.run(UserApplication.class);System.out.println(run.getBeanFactory());}
}

3、实现具体业务类

@RestController
public class UserController {@Autowiredprivate UserService userService;@GetMapping("test")public String test() {return userService.test();}
}
@Service
public class UserService {public String test() {return "hello  springboot";}
}

4、启动测试访问

在这里插入图片描述

三、项目地址

git地址

相关文章:

手写springboot

前言 首先确定springboot在spring基础上主要做了哪些改动&#xff1a;内嵌tomcatspi技术动态加载 一、基本实现 1. 建一个工程目录结构如下&#xff1a; springboot: 源码实现逻辑 user : 业务系统2.springboot工程项目构建 1. pom依赖如下 <dependencies>…...

报错Uncaught (in promise) Error: Manifest request to...

在使用nuxt框架时&#xff0c;出现如下报错&#xff1a; 解决方案&#xff1a; 不要打开两个以上的开发者工具更换nuxt的端口号 参考资料&#xff1a;https://github.com/nuxt/nuxt.js/issues/6202...

微信私域更好玩了

之前分享过&#xff0c;“小绿书”“公众号文章转音频”等内测中或悄悄已升级的功能。 其实&#xff0c;微信还在内测很多新功能&#xff0c;只是没公开 今天&#xff0c;小编又发现新升级 就是『附近』功能 增加了一个本地生活的入口&#xff0c;这里面是短视频和图文 展示…...

基于ant-design的a-modal自定义vue拖拽指令

写一个dragDialog.js 在main.js中引入 import ‘./core/directives/dragDialog.js’ // 让 dialog 支持鼠标拖动 import Vue from vueVue.directive(DragDialog, {update: function (el, binding, vnode) {if (!binding.value || !binding.value.reset) returnconst dialog e…...

【ES】笔记-模板字符串(template string)是增强版的字符串`${expresions}`

模板字符串 传统的 JavaScript 语言&#xff0c;输出模板通常是这样写的&#xff08;下面使用了 jQuery 的方法&#xff09;。 $(#result).append(There are <b> basket.count </b> items in your basket, <em> basket.onSale </em> are on sal…...

利用 OLE 对象漏洞的 HWP 恶意文件浮出水面

ASEC 分析人员发现了一个利用 OLE 对象的恶意 HWP 文件&#xff0c;尽管其使用了 2020 年就被识别的恶意 URL&#xff0c;但仍然使用了 Flash 漏洞&#xff08;CVE-2018-15982&#xff09;&#xff0c;需要用户谨慎对待。 打开 HWP 文件时会在 %TEMP%文件夹中生成如下文件。攻…...

【CSS】倾斜按钮

效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"/><meta http-equiv"X-UA-Compatible" content"IEedge"/><meta name"viewport" content"widthdevice-…...

js 正则表达式

js 正则表达式 http://tool.oschina.net/regex https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions 11 22...

心理咨询预约管理系统javaweb医院挂号jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 心理咨询预约管理系统javaweb MVC模式&#xff0c;普…...

Linux中安装Node

安装 先从 官方网站 下载安装包&#xff0c;有时 node 版本太新会导致失败&#xff0c;详见下方的常见问题第2点 cd /home // 创建目录&#xff0c;将下载好的 node 安装包上传到此目录 mkdir Download mkdir /usr/local/lib/node解压 // 解压&#xff0c;前面是文件当前路径…...

爬虫011_元组高级操作_以及字符串的切片操作---python工作笔记030

获取元组的下标对应的值 注意元组是不可以修改值的,只能获取不能修改 但是列表是可以修改值的对吧...

JVM虚拟机篇

JVM组成 面试题1&#xff1a;什么是程序计数器&#xff1f; 面试题2&#xff1a;你能给我详细的介绍Java堆吗? 面试题3&#xff1a;什么是虚拟机栈&#xff1f; 面试题4&#xff1a;垃圾回收是否涉及栈内存&#xff1f; 垃圾回收主要指就是堆内存&#xff0c;当栈帧弹栈以后…...

Flutter 让软键盘不再自动弹起

1、问题说明&#xff1a; 在开发中&#xff0c;经常遇到这种事&#xff0c;一个页面有输入框&#xff0c;点击输入框后&#xff0c;会弹起软键盘&#xff0c;同时输入框会聚焦&#xff0c;手动收起软键盘后&#xff0c;点击另一个按钮前往下一个页面或者显示一个弹窗&#xff0…...

k8s 自身原理 1

咱们从 pod 一直分享到最近的 Statefulset 资源&#xff0c;到现在好像我们只是知道如何使用 k8s&#xff0c;如何按照 k8s 设计好的规则去应用&#xff0c;去玩 k8s 仔细想想&#xff0c;对于 k8s 自身的内在原理&#xff0c;我们好像还不是很清楚&#xff0c;对于每一个资源…...

在CPU上安装部署chatglm-6b实用经验分享

chatglm-6b很强&#xff0c;很多同学都想自己试一试&#xff0c;但不是每个人都有GPU、高端显卡的环境&#xff0c;大多数同学都是一台普通的笔记本。 笔者这里分享一下在自己的8G内存&#xff0c;intel i3笔记本上安装部署chatglm-6b的实际经验。有很多网站都分享了一些经验&…...

Mermaid系列之FlowChart流程图

一.欢迎来到我的酒馆 介绍mermaid下&#xff0c;Flowchat流程图语法。 目录 一.欢迎来到我的酒馆二.什么是mermiad工具三.在vs code中使用mermaid四.基本语法 二.什么是mermiad工具 2.1 mermaid可以让你使用代码来创建图表和可视化效果。mermaid是一款基于javascript语言的图表…...

分享Java技术下AutojsPro7云控代码

引言 有图有真相&#xff0c;那短视频就更是真相了。下面是三大语言的短视频。 Java源码版云控示例&#xff1a; Java源码版云控示例在线视频 核心技术&#xff1a;各个编程语言的WebSocket技术。 Java&#xff1a;Nettey、Net&#xff1a;Fleck、Python&#xff1a;Tornad…...

黑马机器学习day2

1.1sklearn转换器和估计器 转换器和预估器&#xff08;estimator&#xff09; 1.1.1转换器 实例化一个转换器类 Transformer调用fit_transform() 转换器调用有以下几种形式&#xff1a; fit_transformfittransform 1.1.2估计器 在sklearn中&#xff0c;估计器是一…...

rosdep init || rosdep update || 出错?链接失败?换源!

问题简述 本文主要解决rosdep init失败&#xff0c;rosdep update失败的问题。 rosdep init失败和rosdep update失败&#xff0c;最常见的问题就是网络链接失败。有的朋友会说“诶我使用了tz啊”&#xff0c;但是这里的链接失败对time out的要求不低&#xff0c;虽然你使用了…...

流量、日志分析分析

这周主要以做题为主 先找找理论看然后在buuctrf以及nssctf找了题做 了解wireshark Wireshark是一款开源的网络协议分析软件&#xff0c;具有录制和检查网络数据包的功能&#xff0c;可以深入了解网络通信中的传输协议、数据格式以及通信行为。Wireshark可以捕获发送和接收的数…...

驱动管理工具:释放磁盘空间的开源解决方案

驱动管理工具&#xff1a;释放磁盘空间的开源解决方案 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 当你的系统频繁弹出磁盘空间不足警告&#xff0c;而C盘又找不到明显的大文件时&am…...

手柄不兼容PC游戏?试试ViGEmBus的虚拟控制器仿真技术

手柄不兼容PC游戏&#xff1f;试试ViGEmBus的虚拟控制器仿真技术 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 你是否遇到过这样的情况&#xff1a;新买的…...

Qwen2.5-14B-Instruct深度微调实录:像素剧本圣殿开源剧本创作指南

Qwen2.5-14B-Instruct深度微调实录&#xff1a;像素剧本圣殿开源剧本创作指南 1. 项目概览 像素剧本圣殿&#xff08;Pixel Script Temple&#xff09;是一款基于Qwen2.5-14B-Instruct大模型深度微调的专业剧本创作工具。这个开源项目将前沿AI技术与复古像素美学相结合&#…...

intv_ai_mk11惊艳效果:输入‘用小学生能懂的话解释Transformer’→输出比喻+图示描述+小练习

intv_ai_mk11惊艳效果&#xff1a;输入用小学生能懂的话解释Transformer→输出比喻图示描述小练习 1. 效果展示开场 当我第一次尝试让intv_ai_mk11解释Transformer这个复杂概念时&#xff0c;我完全没想到它会给出如此惊艳的答案。我输入了一个看似简单的请求&#xff1a;&qu…...

别只埋头改Bug!从Flutter高德地图鸿蒙适配,聊聊跨平台插件架构设计的最佳实践

从Flutter高德地图鸿蒙适配看跨平台插件架构设计的黄金法则 当Flutter遇上鸿蒙&#xff0c;开发者们既兴奋又忐忑。兴奋的是跨平台开发框架与国产操作系统的强强联合&#xff0c;忐忑的是两者结合带来的技术适配挑战。去年我们团队在将高德地图SDK集成到Flutter鸿蒙应用时&…...

GG3M 项目独家原创理论:元模型的形式化结构

GG3M 项目独家原创理论&#xff1a;元模型的形式化结构本元模型是GG3M 贾子公理体系的形式化数学内核&#xff0c;是对全尺度复杂系统&#xff08;个人认知、企业经营、城市治理、国家战略、文明演化&#xff09;底层规律的顶层抽象&#xff0c;是 GG3M 所有子模型、应用场景、…...

Qwen3.5-4B-Claude-Opus一文详解:GGUF量化模型在低延迟推理场景下的优势

Qwen3.5-4B-Claude-Opus一文详解&#xff1a;GGUF量化模型在低延迟推理场景下的优势 1. 模型概述 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是基于Qwen3.5-4B架构的推理蒸馏模型&#xff0c;特别强化了结构化分析、分步骤回答以及代码与逻辑类问题的处理能力。该…...

Wan2.2-I2V-A14B环境配置避坑指南:解决C盘空间不足与依赖冲突

Wan2.2-I2V-A14B环境配置避坑指南&#xff1a;解决C盘空间不足与依赖冲突 1. 引言 最近在Windows系统上配置Wan2.2-I2V-A14B环境时&#xff0c;我发现很多朋友都遇到了相同的问题&#xff1a;C盘空间莫名其妙被占满、各种依赖包冲突报错、CUDA版本不匹配等等。作为一个踩过所…...

Fish Speech 1.5API文档增强:OpenAPI 3.0规范生成与Swagger UI集成

Fish Speech 1.5 API文档增强&#xff1a;OpenAPI 3.0规范生成与Swagger UI集成 1. 引言&#xff1a;为什么需要API文档增强&#xff1f; 在实际开发中&#xff0c;我们经常遇到这样的场景&#xff1a;团队新成员需要快速了解API接口&#xff0c;第三方开发者想要集成语音合成…...

快速验证汽车电子创意:用快马AI十分钟搭建CAN总线通信原型

在汽车电子和工业控制领域&#xff0c;CAN总线通信是最基础也最重要的技术之一。最近我在做一个车载设备的小项目&#xff0c;需要快速验证CAN通信功能。传统开发方式往往要花大量时间搭建底层驱动&#xff0c;但这次我尝试用InsCode(快马)平台的AI辅助功能&#xff0c;居然十分…...