手写springBoot启动器

news2025/2/26 3:39:16

提示:springboot原理,手写springboot启动器,手写模拟SpringBoot启动过程、手写模拟SpringBoot自动配置功能

文章目录

  • 前言
  • 一、本文内容
    • 1、手写模拟SpringBoot启动过程
    • 2、手写模拟SpringBoot自动配置功能
  • 二、项目总体介绍
  • 三、代码实现(手写模拟SpringBoot启动过程)
    • 1、引入依赖
    • 2、定义controller、service
    • 3、核心注解和核心类
      • 3.1、@ZhouyuSpringBootApplication注解
      • 3.2、ZhouyuSpringApplication类
      • 3.3、MyApplication(自定义启动类)
    • 4、run方法要实现的逻辑
      • 4.1、创建Spring容器
      • 4.2、启动Tomcat
      • 4.3、调用startTomcat方法
      • 4.4、 测试
  • 四、代码实现(手写模拟SpringBoot自动配置功能)
    • 1、期望效果
    • 2、代码实现:
      • 2.1、定义接口
      • 2.2、实现接口
      • 2.3、修改run方法
      • 2.4、模拟实现条件注解
      • 2.5、使用条件注解
      • 2.6、解释整体SpringBoot启动逻辑
      • 2.7、发现自动配置类
        • 2.7.1、
        • 2.7.2
        • 2.7.3、
        • 2.7.4、
        • 2.7.5、
      • 2.8、测试
        • 2.8.1、如果有tomcat依赖,自动是tomcat
        • 2.8.2、如果有jetty依赖,自动是jetty
  • 总结


前言

大家都知道springboot号称“手脚架”,用默认大于配置的方式,方便我们放弃写冗余复杂的配置文件。但了解的可能不是那么深刻,具体的执行过程,也没有那么清晰。通过手写模拟实现一个Spring Boot,让大家能以非常简单的方式就能知道Spring Boot大概是如何工作的。本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!


完全的git代码地址:地址。建议大家下载代码,通过代码阅读,更加直管。

一、本文内容

1、手写模拟SpringBoot启动过程

2、手写模拟SpringBoot自动配置功能

二、项目总体介绍

建一个工程,两个Module:

  1. springboot模块,表示正常使用springboot框架的实现
  2. user包,表示用户业务系统,用我们自己手写的springboot框架来实现

在这里插入图片描述

三、代码实现(手写模拟SpringBoot启动过程)

1、引入依赖

首先,SpringBoot是基于的Spring,所以我们要依赖Spring,然后我希望我们模拟出来的SpringBoot也支持Spring MVC的那一套功能,所以也要依赖Spring MVC,包括Tomcat等,所以在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>

2、定义controller、service

然后定义相关的Controller和Service:
在这里插入图片描述

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("test")
    public String test(){
        return userService.test();
    }
}

因为我们模拟实现的是SpringBoot,而不是SpringMVC,所以我直接在user包下定义了UserController和UserService,最终我希望能运行MyApplication中的main方法,就直接启动了项目,并能在浏览器中正常的访问到UserController中的某个方法。

3、核心注解和核心类

我们在真正使用SpringBoot时,核心会用到SpringBoot一个类和注解:

  1. @SpringBootApplication,这个注解是加在应用启动类上的,也就是main方法所在的类
  2. SpringApplication,这个类中有个run()方法,用来启动SpringBoot应用的
    所以我们也来模拟实现他们。

3.1、@ZhouyuSpringBootApplication注解

一个@ZhouyuSpringBootApplication注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
public @interface ZhouyuSpringBootApplication {
}

3.2、ZhouyuSpringApplication类

一个用来实现启动逻辑的ZhouyuSpringApplication类。

public class ZhouyuSpringApplication {

    public static void run(Class clazz){

    }

}

3.3、MyApplication(自定义启动类)

有了以上两者,我们就可以在MyApplication中来使用了,比如:

@ZhouyuSpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        ZhouyuSpringApplication.run(MyApplication.class);
    }
}

现在用来是有模有样了,但中看不中用,所以我们要来好好实现以下run方法中的逻辑了。

4、run方法要实现的逻辑

run方法中需要实现什么具体的逻辑呢?
首先,我们希望run方法一旦执行完,我们就能在浏览器中访问到UserController,那势必在run方法中要启动Tomcat,通过Tomcat就能接收到请求了。大家如果学过Spring MVC的底层原理就会知道,在SpringMVC中有一个Servlet非常核心,那就是DispatcherServlet,这个DispatcherServlet需要绑定一个Spring容器,因为DispatcherServlet接收到请求后,就会从所绑定的Spring容器中找到所匹配的Controller,并执行所匹配的方法。
所以,在run方法中,我们要实现的逻辑如下:

  1. 创建一个Spring容器
  2. 创建Tomcat对象
  3. 生成DispatcherServlet对象,并且和前面创建出来的Spring容器进行绑定
  4. 将DispatcherServlet添加到Tomcat中
  5. 启动Tomcat

4.1、创建Spring容器

public class ZhouyuSpringApplication {

    public static void run(Class clazz){
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(clazz);
        applicationContext.refresh();

        
    }
}

我们创建的是一个AnnotationConfigWebApplicationContext容器,并且把run方法传入进来的class作为容器的配置类,比如在MyApplication的run方法中,我们就是把MyApplication.class传入到了run方法中,最终MyApplication就是所创建出来的Spring容器的配置类,并且由于MyApplication类上有@ZhouyuSpringBootApplication注解,而@ZhouyuSpringBootApplication注解的定义上又存在@ComponentScan注解,所以AnnotationConfigWebApplicationContext容器在执行refresh时,就会解析MyApplication这个配置类,从而发现定义了@ComponentScan注解,也就知道了要进行扫描,只不过扫描路径为空,而AnnotationConfigWebApplicationContext容器会处理这种情况,如果扫描路径会空,则会将MyApplication所在的包路径做为扫描路径,从而就会扫描到UserService和UserController。

所以Spring容器创建完之后,容器内部就拥有了UserService和UserController这两个Bean。

4.2、启动Tomcat

我们用的是Embed-Tomcat,也就是内嵌的Tomcat,真正的SpringBoot中也用的是内嵌的Tomcat,而对于启动内嵌的Tomcat,也并不麻烦,代码如下:

public 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(contextPath, "dispatcher", new DispatcherServlet(applicationContext));
    context.addServletMappingDecoded("/*", "dispatcher");
    
    try {
        tomcat.start();
    } catch (LifecycleException e) {
        e.printStackTrace();
    }
    
}

代码虽然看上去比较多,但是逻辑并不复杂,比如配置了Tomcat绑定的端口为8081,后面向当前Tomcat中添加了DispatcherServlet,并设置了一个Mapping关系,最后启动,其他代码则不用太过关心。

而且在构造DispatcherServlet对象时,传入了一个ApplicationContext对象,也就是一个Spring容器,就是我们前文说的,DispatcherServlet对象和一个Spring容器进行绑定。

4.3、调用startTomcat方法

接下来,我们只需要在run方法中,调用startTomcat即可:

public static void run(Class clazz){
    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
    applicationContext.register(clazz);
    applicationContext.refresh();
    
    startTomcat(applicationContext);
    
}

4.4、 测试

实际上代码写到这,一个极度精简版的SpringBoot就写出来了,比如现在运行MyApplication,就能正常的启动项目,并能接收请求。
启动能看到Tomcat的启动日志:
在这里插入图片描述
然后在浏览器上访问:http://localhost:8081/test ,也能正常的看到结果:
在这里插入图片描述
此时,你可以继续去写其他的Controller和Service了,照样能正常访问到,而我们的业务代码中仍然只用到了ZhouyuSpringApplication类和@ZhouyuSpringBootApplication注解。

四、代码实现(手写模拟SpringBoot自动配置功能)

虽然我们前面已经实现了一个比较简单的SpringBoot,不过我们可以继续来扩充它的功能,比如现在我有这么一个需求,这个需求就是我现在不想使用Tomcat了,而是想要用Jetty,那该怎么办?

1、期望效果

我们前面代码中默认启动的是Tomcat,那我现在想改成这样子:
1.如果项目中有Tomcat的依赖,那就启动Tomcat
2.如果项目中有Jetty的依赖就启动Jetty
3.如果两者都没有则报错
4.如果两者都有也报错
这个逻辑希望SpringBoot自动帮我实现,对于程序员用户而言,只要在Pom文件中添加相关依赖就可以了,想用Tomcat就加Tomcat依赖,想用Jetty就加Jetty依赖。

那SpringBoot该如何实现呢?

2、代码实现:

2.1、定义接口

我们知道,不管是Tomcat还是Jetty,它们都是应用服务器,或者是Servlet容器,所以我们可以定义接口来表示它们,这个接口叫做WebServer(别问我为什么叫这个,因为真正的SpringBoot源码中也叫这个)。
并且在这个接口中定义一个start方法:

public interface WebServer {
    
    public void start();
    
}

2.2、实现接口

有了WebServer接口之后,就针对Tomcat和Jetty提供两个实现类:

public class TomcatWebServer implements WebServer{

    @Override
    public void start() {
        System.out.println("启动Jetty");
    }
}
public class JettyWebServer implements WebServer{

    @Override
    public void start() {
       System.out.println("启动Tomcat");
    }
}

2.3、修改run方法

而在ZhouyuSpringApplication中的run方法中,我们就要去获取对应的WebServer,然后启动对应的webServer,代码为:

public static void run(Class clazz){
    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
    applicationContext.register(clazz);
    applicationContext.refresh();
    
    WebServer webServer = getWebServer(applicationContext);
    webServer.start();
    
}

public static WebServer getWebServer(ApplicationContext applicationContext){
    return null;
}

这样,我们就只需要在getWebServer方法中去判断到底该返回TomcatWebServer还是JettyWebServer。

前面提到过,我们希望根据项目中的依赖情况,来决定到底用哪个WebServer,我就直接用SpringBoot中的源码实现方式来模拟了。

2.4、模拟实现条件注解

首先我们得实现一个条件注解@ZhouyuConditionalOnClass,对应代码如下:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(ZhouyuOnClassCondition.class)
public @interface ZhouyuConditionalOnClass {
    String value() default "";
}

注意核心为@Conditional(ZhouyuOnClassCondition.class)中的ZhouyuOnClassCondition,因为它才是真正得条件逻辑:

public class ZhouyuOnClassCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotationAttributes = 
            metadata.getAnnotationAttributes(ZhouyuConditionalOnClass.class.getName());

        String className = (String) annotationAttributes.get("value");

        try {
            context.getClassLoader().loadClass(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

具体逻辑为,拿到@ZhouyuConditionalOnClass中的value属性,然后用类加载器进行加载,如果加载到了所指定的这个类,那就表示符合条件,如果加载不到,则表示不符合条件。

2.5、使用条件注解

有了条件注解,我们就可以来使用它了,那如何实现呢?
这里就要用到自动配置类的概念,我们先看代码:

@Configuration
public class WebServiceAutoConfiguration {

    @Bean
    @ZhouyuConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatWebServer tomcatWebServer(){
        return new TomcatWebServer();
    }

    @Bean
    @ZhouyuConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyWebServer jettyWebServer(){
        return new JettyWebServer();
    }
}

这个代码还是比较简单的,通过一个WebServiceAutoConfiguration的Spring配置类,在里面定义了两个Bean,一个TomcatWebServer,一个JettyWebServer,不过这两个要生效的前提是符合当前所指定的条件,比如:

  1. 只有存在"org.apache.catalina.startup.Tomcat"类,那么才有TomcatWebServer这个Bean
  2. 只有存在"org.eclipse.jetty.server.Server"类,那么才有TomcatWebServer这个Bean

并且我们只需要在ZhouyuSpringApplication中getWebServer方法,如此实现:

public static WebServer getWebServer(ApplicationContext applicationContext){
    // key为beanName, value为Bean对象
    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();
}

2.6、解释整体SpringBoot启动逻辑

这样整体SpringBoot启动逻辑就是这样的:
1.创建一个AnnotationConfigWebApplicationContext容器
2.解析MyApplication类,然后进行扫描
3.通过getWebServer方法从Spring容器中获取WebServer类型的Bean
4.调用WebServer对象的start方法

有了以上步骤,我们还差了一个关键步骤,就是Spring要能解析到WebServiceAutoConfiguration这个自动配置类,因为不管这个类里写了什么代码,Spring不去解析它,那都是没用的,此时我们需要SpringBoot在run方法中,能找到WebServiceAutoConfiguration这个配置类并添加到Spring容器中。

MyApplication是Spring的一个配置类,但是MyApplication是我们传递给SpringBoot,从而添加到Spring容器中去的,而WebServiceAutoConfiguration就需要SpringBoot去自动发现,而不需要程序员做任何配置才能把它添加到Spring容器中去,而且要注意的是,Spring容器扫描也是扫描不到WebServiceAutoConfiguration这个类的,因为我们的扫描路径是"com.zhouyu.user",而WebServiceAutoConfiguration所在的包路径为"com.zhouyu.springboot"。

那SpringBoot中是如何实现的呢?通过SPI,当然SpringBoot中自己实现了一套SPI机制,也就是我们熟知的spring.factories文件,那么我们模拟就不搞复杂了,就直接用JDK自带的SPI机制。

2.7、发现自动配置类

为了实现这个功能,以及为了最后的效果演示,我们需要把springboot源码和业务代码源码拆分两个maven模块,也就相当于两个项目,最后的源码结构为:
在这里插入图片描述

2.7.1、

现在我们只需要在springboot项目中的resources目录下添加如下目录(META-INF/services)和文件:
在这里插入图片描述

2.7.2

SPI的配置就完成了,相当于通过com.zhouyu.springboot.AutoConfiguration文件配置了springboot中所提供的配置类。并且提供一个接口:

public interface AutoConfiguration {
}
2.7.3、

并且WebServiceAutoConfiguration实现该接口:

@Configuration
public class WebServiceAutoConfiguration implements AutoConfiguration {

    @Bean
    @ZhouyuConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatWebServer tomcatWebServer(){
        return new TomcatWebServer();
    }

    @Bean
    @ZhouyuConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyWebServer jettyWebServer(){
        return new JettyWebServer();
    }
}
2.7.4、

然后我们再利用spring中的@Import技术来导入这些配置类,我们在@ZhouyuSpringBootApplication的定义上增加如下代码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
@Import(ZhouyuImportSelect.class)
public @interface ZhouyuSpringBootApplication {
}
2.7.5、

ZhouyuImportSelect类为:

public class ZhouyuImportSelect implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        ServiceLoader<AutoConfiguration> serviceLoader = ServiceLoader.load(AutoConfiguration.class);

        List<String> list = new ArrayList<>();
        for (AutoConfiguration autoConfiguration : serviceLoader) {
            list.add(autoConfiguration.getClass().getName());
        }

        return list.toArray(new String[0]);
    }
}

2.8、测试

这就完成了从com.zhouyu.springboot.AutoConfiguration文件中获取自动配置类的名字,并导入到Spring容器中,从而Spring容器就知道了这些配置类的存在,而对于user项目而言,是不需要修改代码的。

2.8.1、如果有tomcat依赖,自动是tomcat

此时运行MyApplication,就能看到启动了Tomcat:

在这里插入图片描述

2.8.2、如果有jetty依赖,自动是jetty

此时运行MyApplication,就能看到启动了jetty


总结

文章可能写的比较乱,理解起来没那么方便。不过可以下载下来git的代码,自己执行一遍,更容易理解。梦在前方,路在脚下,大家一起努力吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1383050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Adobe Illustrator 2023--AI2023中文

Adobe Illustrator 2023是一款专业的矢量图形设计软件&#xff0c;广泛应用于印刷、Web、视频和移动设备的设计制作。它提供了丰富的绘图工具、矢量图形编辑功能和灵活的排版设计工具&#xff0c;帮助用户快速高效地制作出精美的设计作品。相较于其他设计软件&#xff0c;Adobe…

分享7款前端CSS动画特效源码(附在线演示)

精选7款前端CSS动画特效源码 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 CSS飞行的荷包蛋 CSS荷包蛋动画 荷包蛋会向右前方加速飞行 期间还能看到周围的气流匆匆飞过 以下图片只是简单的模型没有具体的动画效果最终动画…

Python读取log文件报错“UnicodeDecodeError”

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 问题描述&#xff1a; 写了一个读取log文件的Python脚本&#xff1a; # -*- coding:utf-8 -*- import os import numpy as np …

手撕乘积(**Multiplication** **Product**): 穷举和图示(1)

手撕乘积(Multiplication & Product): 穷举和图示(1) 乘积 r ⋅ s ∑ i 1 s r r r ⋯ r ⏟ s times ∑ j 1 r s s s ⋯ s ⏟ r times r\cdot s\sum _{i1}^{s}r\underbrace {rr\cdots r} _{s{\text{ times}}}\sum _{j1}^{r}s\underbrace {ss\cdots s} _{r{\tex…

怎么把workspace的数据导入到simulink查看波形?

仿真截图&#xff1b; 示例代码&#xff1a; sampleTime 0.001; %设置采样时间 numSteps 1/sampleTimes; %设置时间矩阵长度 time sampleTime*(0:numSteps-1); %定义时间矩阵 time time; %时间矩阵转置 data sin…

【Maven】008-Maven 私服搭建与使用

【Maven】008-Maven 私服搭建与使用 文章目录 【Maven】008-Maven 私服搭建与使用一、概述1、简介2、建立私服后依赖查找和下载逻辑第一步&#xff1a;请求本地仓库第二步&#xff1a;请求 Maven 私服第三步&#xff1a;请求外部远程仓库&#xff08;远程中央仓库等&#xff09…

SOMEIP学习总结

SOMEIP学习总结&#xff08;包含VSOMEIP库&#xff09; 一.基本概念 1.SOMEIP支持TCP和UDP两种传输方式 ​ 其中&#xff0c;SOMEIP-SD的消息都是通过UDP发送的 2.SOMEIP支持如下中间件特性&#xff1a; Serialization – transforming into and from on-wire representati…

深入解析JavaScript中构造函数和new操作符

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ 目录 ✨ 前言 ✨ 正文 第一节:构造函数 第二节:new操作符 第三节:实例与原型 ✨ 结语 ✨ 前言…

java poi导出excel合并单元格

导出效果 代码&#xff1a; import java.math.BigDecimal;public class CwmonthlyPlanSub0Bean {/*** 主键*/private Long id;/*** 付款类*/private String fkl;/*** 付款事项*/private String fksx;/*** 本期预算金额*/private BigDecimal bqysje;/*** * 电汇金额*/private B…

CSS 弹幕按钮动画

<template><view class="content"><button class="btn-23"><text class="text">弹幕按钮</text><text class="marquee">弹幕按钮</text></button></view></template><…

移动硬盘无法识别处理办法

今天这里做一下总结&#xff0c;我现在手上有一个移动硬盘&#xff0c;插入win10电脑是有盘号的&#xff0c;但是 但是点击就出问题 解决办法 安装DiskGenius 下载网址在https://www.diskgenius.cn/download.php 下载之后解压安装就行&#xff0c;非常简单&#xff0c;然后…

Provide/Inject 依赖注入(未完待续)

父组件传递给子组件数据&#xff0c;通过props&#xff0c;但是需要逐层传递 provide/Inject 的推出就是为了解决这个问题&#xff0c;它提供了一种组件之间共享此类值的方式,不必通过组件树每层级显示地传递props 目的是为了共享那些被 认为对于一个组件树而言是全局的数据 p…

【LeetCode: 57. 插入区间+分类讨论+模拟】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

12.3在应用层使用SPI总线

在SPI总线驱动框架中提供了一个spidev 的字符设备驱动&#xff0c;在应用层可以通过它来访问SPI总线。 应用层访问SPI总线的步骤 编写spidev设备树节点&#xff0c;在SPI总线的设备树节点下添加spidev设备的树节点&#xff0c;设备树示例如下所示&#xff1a; spidev0: spid…

ASCII编码:计算机文本通信的基石

ASCII&#xff08;美国信息交换标准代码&#xff09;编码是一种将字符与数字相互映射的编码系统&#xff0c;它为现代计算机文本通信奠定了基础。本文将从多个方面介绍ASCII编码的原理、发展历程、应用及其在现实场景中的优势&#xff0c;帮助您深入了解这一重要的编码技术。 …

C++进阶--红黑树

红黑树 一、红黑树的概念二、红黑树的性质三、红黑树结点的定义四、红黑树的插入五、红黑树的验证七、红黑树的查找七、红黑树与AVL树的比较七、完整代码RBTree.h 一、红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色…

QT -狗狗管理工具

QT -狗狗管理工具 一、演示效果二、UML三、关键代码四、程序链接 一、演示效果 二、UML 三、关键代码 #include <QFrame> #include <QHBoxLayout> #include <QVBoxLayout> #include <QLabel> #include <QSizePolicy> #include <QDialog> …

【深度学习每日小知识】Computer Vision 计算机视觉

计算机视觉是人工智能的一个领域&#xff0c;涉及算法和系统的开发&#xff0c;使计算机能够解释、理解和分析来自周围世界的视觉数据。这包括从静态图像到视频流甚至 3D 环境的一切。 使用对象检测和特征提取等方法&#xff0c;计算机视觉本质上需要从视觉输入中提取有用信息…

大模型微调及生态简单介绍

大模型 大模型生态OpenAI大模型生态&#xff1a; 全球开源大模型性能评估榜单中文语言模型——ChatGLM基于ChatGLM的多模态⼤模型 大模型微调LLM⼤语⾔模型 ⼀般训练过程为什么需要微调高效微调技术⽅法概述⾼效微调⽅法一&#xff1a;LoRA微调方法高效微调⽅法⼆&#xff1a;P…

linux 网络设置

查看linux基础的网络配置 命令 网关route -nip 地址ifconfig / ip aDNS 服务器cat /etc/resolv.conf主机名hostname路由route -n网络连接状态ss / netstat 一&#xff0c;ifconfig 查看网络接口信息 &#xff08;一&#xff09;ifconfig …