仿SpringBoot启动Dome实现

news2024/9/22 3:51:26

文章目录

  • 前言
  • 环境搭建
    • 依赖
    • 项目结构
  • 实现
    • 启动
    • 获取服务器
    • 自动配置
    • 启动Tomcat
  • 总结

前言

填一下以前这篇博文:如何纯注解整合Spring SpringMVC Mybatis埋下的坑,我们来简单的了解一下SpringBoot它做的一些自动配置是怎么一回事,同时也看看SpringBoot如何做到内置服务器的(其实这两货是一样的)

那么在开始之前呢,我们先简单回顾一下,Spring,SpringMVC,SpringBoot的一个关系。首先我们来聊一下这个Spring,这个家伙呢,在为我们开发项目的时候呢,提供了很多有利于项目开发的解决方案,其中比较出名的是它提供的IOC,和 AOP这两个家伙便于我们对项目的对象进行管理和功能的实现。MVC呢是为了解决Servlet这个玩意不好用,同时为了高效开发,在Dispatch这个地方做了点手脚,让请求经过MVC,之后由我们按照MVC要求的风格编写出来的代码执行对应的逻辑。也就是说,Tomcat提供Servlet操作服务器,MVC在Servlet的基础上做代码优化省略不必要的额外开发,说白了做了一个工具包。但是这个工具包基于Spring来实现,同时可以共享IOC容器,也就是说可以通过Spring结合其他的组件,例如SpringData,或者国内比较常用的Mybatis,完成最基础的CURD的项目的开发,但是由于为了能够让Spring去不断整合更多的玩意,实现更加复杂的功能,于是SpringBoot做了一件事情就是约定大于配置,于是把很多东西直接整合好了。也就是做了一个类似于脚手架的东西,开发者不需要从0开始配置组合、换一句话说,根据任务需求,有一个配置好了大部分组件的Spring。于是你拿过来改一下就差不多了。并且SpringBoot提供了一种约束大家按照这格约束来,就可以更快的组合项目。比如我们的starter,starter就像一个组件,SpringBoot是一个架子,把Starter放进来,就完成了大部分的组装工作。此外,对于SpringBoot而言它还直接把服务器默认给配置好了,项目启动时只需要配置端口即可。

那么我们这边要做的就是看看这个玩意那些自动配置咋做的,如何把服务器给内置进去的。

环境搭建

首先我们来看到一个SpringBoot启动类,我们来看到有什么东西。

在这里插入图片描述

这里有一个注解,然后有一个run方法,方法传递类对象,以及参数,参数也可以不传递。

之后项目启动的时候,服务器就启动了。那么我们这边也是创建一个dome,我们来简单仿造一下怎么做的。

这边创建了这样的项目:
在这里插入图片描述

这里的话是创建了一个root工程的,没啥作用,就是用来聚合这两个项目的。上面那个就是我们要仿造的dome,下面是我们模仿使用。

依赖

依赖的话分别如下:
由于SpringBoot是自己内置了几个服务器的,因此我们这边也是做一个模拟,也要导入多格服务器,比如Tomcat和Jetty,但是呢,默认的是Tomcat,所以的话,我们这边对Jetty服务器要做一个避免依赖传递。

<?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.huterox</groupId>
    <artifactId>springboot</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-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-aop</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>


        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.4.48.v20220622</version>
            <optional>true</optional>
        </dependency>

    </dependencies>

</project>

那么使用的那个就简单了:

<?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.huterox</groupId>
    <artifactId>useboot</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>com.huterox</groupId>
            <artifactId>springboot</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

直接使用就好了。

项目结构

依赖导入完了,但是还不够,因为的话,在用SpringBoot的时候,我们以前只需要导入SpringBoot和web-starter的依赖就可以处理请求了,那么我们也要实现这个。而且这边都要做内置服务器,因此也需要做出来。

首先看到我们的使用,非常简单。项目结构如下:
在这里插入图片描述

package com.huterox;


import com.huterox.annoation.HSpringBootApplication;
import com.huterox.boot.HSpringApplication;

@HSpringBootApplication
public class UseBootApplication {

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

package com.huterox.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserBootController {

    @GetMapping("/hello")
    public String hello(){
        return "hello world";
    }
}

之后的话是我们仿造的dome的结构。
在这里插入图片描述
在这里插入图片描述

实现

OK,这个就是咱们最基本的实现。
首先自然就是这个启动类,以及对应的启动的注解了。

启动

我们先来看到我们的类实现。


public class HSpringApplication {
    /**
     * 启动Tomcat 以及对应上下文 给mvc
     * */
    public static void run(Class  clazz){
        AnnotationConfigWebApplicationContext applicationContext = new
                AnnotationConfigWebApplicationContext();

        applicationContext.register(clazz);
        applicationContext.refresh();

        WebServer webServer = getWebServer(applicationContext);
        webServer.start();

    }
	
	//获取服务器,把服务器实例化在容器里面,然后拿出来启动,但是默认支持一个
    private static WebServer getWebServer(WebApplicationContext applicationContext) {

        Map<String, WebServer> beansOfType = applicationContext.getBeansOfType(WebServer.class);
        if(beansOfType.size()==0){
            throw new NullPointerException("未找到对应服务器依赖");
        }else if(beansOfType.size()>1){
            throw new RuntimeException("期望存在一个服务器依赖,但是发现多个请指定具体某一个");
        }
        return beansOfType.values().stream().findFirst().get();
    }


}

这里的话我们简单一点,只需要传递类就好了。

之后是注解:

package com.huterox.annoation;


import com.huterox.autoConfig.webServer.auto.WebServerAutoConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ComponentScan
@Import({WebServerAutoConfig.class})
public @interface HSpringBootApplication {
}

我们这块使用到了一个注解@ComponentScan 是我们Spring里面的,那么当我们加载到使用了这个注解的类的时候,Spring会解析上面的注解,发现有@ComponentScan于是就会默认扫描那个所在类下面的所有的包,然后把类放在IOC里面。所以这个也是为什么我们创建SpringBoot项目的时候那个启动类一般是在最外面的。

获取服务器

之后的话我们还要获取服务器,这里我们定义了这个
在这里插入图片描述

一个接口,两个实现类。我们先来看到接口,这里的话我们先简单模拟一下。

public interface WebServer {

    void start();
}

public class JettyServer implements WebServer {
    @Override
    public void start() {
        System.out.println("我是Jetty Jerry的弟弟 Tom抓不到我嘿嘿~");
    }
}

public class TomCatServer implements WebServer {
    @Override
    public void start() {
        System.out.println("我是Tom 我来抓 Jerry的弟弟Jetty");
    }
}

这个实现类的话,我们先这样简单模拟一下,待会我们再来实现具体的功能,这个玩意干嘛的呢,就是用来启动我们服务器的。我们一般启动服务器是例如Tomcat,是配置了XML文件,比如什么路径呀之类的,然后呢去启动。那么我们这边也是只是我们这边先帮你做好基本配置,然后直接帮你启动好,这个配置包括对Tomcat整合MVC的配置。

自动配置

那么这样做还不够,我们还需要写一个配置类。我们刚刚启动类里面是需要获取到我们的服务器实例,并且我们需要放在IOC里面,那么这个时候我们就需要配置类来实现。


@Configuration
public class WebServerAutoConfig {

    @Bean
    @HCondationOnClass("org.apache.catalina.startup.Tomcat")
    public TomCatServer tomCatServer(){
        return new TomCatServer();
    }

    @Bean
    @HCondationOnClass("org.eclipse.jetty.server.Server")
    public JettyServer jettyServer(){
        return new JettyServer();
    }

}

也就是说,和以前不一样的是,以前配置类现在用户自己的项目里面,现在的话我们写在了SpringBoot里面,同时我们还需要加载到这个配置,于是我们还需要在配置当中引入于是我们在启动的时候引入了这个玩意。
在这里插入图片描述

不过值得一提的是,在真正的SpringBoot里面实现是通过这个注解来实现的。
在这里插入图片描述

它里面是这个:
在这里插入图片描述
他也有一个导入,但是导入的自动导入配置的一个选择器。这个玩意是啥呢,这个呢就是负责加载全部的一个自动配置类的东西,因为在SpringBoot里面不可能只有一个东西需要配置,于是有了这个玩意。同时有一个规范,那就是第三方的东西要整合的时候,比如MP,在MP里面可以写好那个自动配置类,然后呢SpringBoot把这个拿到容器里面。没错自动配置类要么是SpringBoot开发人员写好了,要么是第三方平台写好了,当然用户也可以自动定义配置类。那么第三方平台只需要告诉SpringBoot那个自动类在哪就好了。比如Mp的
在这里插入图片描述
这样就好了。但是咱们这块就算了简化一下。

这个时候呢,我们的自动配置类里面有两个服务器,显然是不合适的。需要选择配置。
包括我们的SpringBoot本身也是这样的,如果我们需要使用Jetty的时候呢。我们是排除了Tomcat的依赖然后导入了Jetty的依赖的。
所以的话在实现的时候要做一个条件注入。

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(HCondationClass.class)
public @interface HCondationOnClass {
    String value();
}

之后这样处理


public class HCondationClass implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Map<String, Object> allAnnotationAttributes = metadata.getAnnotationAttributes(HCondationOnClass.class.getName());
        assert allAnnotationAttributes != null;
        String value = (String) allAnnotationAttributes.get("value");
        try {
            Class<?> aClass = Objects.requireNonNull(context.getClassLoader()).loadClass(value);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }

    }
}

这个条件注入也是依赖的Spring的条件注入。

到此我们简要测试一下:
在这里插入图片描述

这个时候的话我们就启动了我们模拟的服务器。

启动Tomcat

但是这个还不够,我们得真的实现一下,这个我们这里只实现一下Tomcat,我们把代码改一下。
接口也换一下:


public class TomCatServer implements WebServer {
    @Override
    public void start(WebApplicationContext applicationContext) {
        Tomcat tomcat = new Tomcat();

        Server server = tomcat.getServer();

        Service service = server.findService("Tomcat");

        Connector connector = new Connector();
        connector.setPort(8081);

        StandardEngine standardEngine = new StandardEngine();
        standardEngine.setDefaultHost("127.0.0.1");

        StandardHost standardHost = new StandardHost();
        standardHost.setName("127.0.0.1");

        String contextPath = "";
        StandardContext standardContext = new StandardContext();
        standardContext.setPath(contextPath);
        standardContext.addLifecycleListener(new Tomcat.FixContextListener());

        standardHost.addChild(standardContext);
        standardEngine.addChild(standardHost);

        service.setContainer(standardEngine);
        service.addConnector(connector);

        tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet(applicationContext));
        standardContext.addServletMappingDecoded("/*","dispatcher");

        try {
            tomcat.start();
        }catch (LifecycleException e){
            e.printStackTrace();
        }
        
    }
}

启动类这样在start传入
在这里插入图片描述
此时可以看到,我们真的启动了并且MVC正常工作。
在这里插入图片描述

在这里插入图片描述

总结

水完了~

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

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

相关文章

【人民币识别】人民币序列号识别【含GUI Matlab源码 908期】

⛄一、简介 本文描述的人民币序列号识别系统实现了从图像预处理到识别结果的过程, 而序列号识别是本文的重要内容.以序列号区域为研究对象, 主要包括图像预处理、图像分割以及序列号识别等过程。 1 图像预处理 人民币图像总体上来说灰度偏高, 灰度值基本上都大于150 (对8位25…

具有平滑正曲线边界的一般凸体的精确闭式闵可夫斯基研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Minecraft 1.19.2 Forge模组开发 04.动画效果物品

我们本次实现一个具有动画效果的物品&#xff0c;本次演示的模型代码均在文末给出 效果演示效果演示效果演示 首先&#xff0c;请确保你的开发包中引入了geckolib依赖&#xff0c;相关教程请参考:Minecraft 1.19.2 Forge模组开发 03.动画生物实体 1.首先我们要使用geckolib制…

(三)操作系统的运行环境

文章目录一、操作系统的运行机制1. 时钟管理2. 中断机制3. 原语4. 系统数据结构5. 系统调用二、操作系统体系结构1. 传统的操作系统结构&#xff08;大内核&#xff09;第一代&#xff1a;无结构OS第二代&#xff1a;模块化结构OS&#xff1a;模块-接口法OS第三代&#xff1a;分…

[附源码]计算机毕业设计springboot学习帮扶网站设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

坦克大战②

1. 我方坦克发射单颗子弹 当发射一颗子弹后&#xff0c;就相当于启动一个线程来控制它的位置坐标&#xff1b;Hero[我方坦克]有子弹的对象&#xff0c;当按下J时&#xff0c;就创建一个发射子弹的线程&#xff0c;通过坐标变化让子弹不停的移动&#xff0c;形成一个射击的效果&…

redis 集群搭建的三种方式

文章目录一、Redis主从二、Redis哨兵三、Redis集群一、Redis主从 二、Redis哨兵 三、Redis集群 下载redis wget http://download.redis.io/releases/redis-5.0.3.tar.gz解压redis tar zxvf redis-5.0.3.tar.gz进行重命名 mv redis-5.0.3 redis安装gcc yum install gcc进入red…

如何学习一门技术

如何学习一门技术 同样的生活&#xff0c;在你经历了一些意外和不如意之后&#xff0c;你再回过头来看&#xff0c;之前你所抱怨的生活其实是一个蛮不错的生活。 罗翔&#xff1a;每一个人都应该拥有学习的能力和权力&#xff0c;真正的知识要能走出书斋&#xff0c;去影响每…

StarkNet 性能路线图

目录 前言 区块限制&#xff1a;Validity Rollups vs L1 为什么 L1 吞吐量有限&#xff1f; 为什么相同的障碍不影响validity rollups&#xff1f; Sequencer 并行化 Cairo-VM 的新 Rust 实现 Rust 对 sequencer重新实现 Provers呢&#xff1f; Summary 参考 前言 St…

详解设计模式:迭代器模式

迭代器模式&#xff08;Iterator Pattern&#xff09;也被称为游标模式&#xff08;Cursor Pattern&#xff09;&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。是一种最简单也最常见的设计模式。 迭代器模式 可以让用户透过特定的接口巡访容器中的每一个元素而不用…

HTML5期末大作业:美食网页主题网站设计与实现——HTML+CSS+JavaScript月饼美食食品企业网站html模板9页面

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

[附源码]计算机毕业设计校园运动会管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux基本工具——vim

Linux编辑器vim什么是vimvim的三种常用模式vim的基本操作命令模式插入模式底行模式搭配vim环境sudo怎么才能让普通用户使用什么是vim vim是linux下一款功能强大&#xff0c;多模式的编辑器。 现阶段有13种模式。 这就是进入vim的方式。 vim的三种常用模式 命令模式 我们第一…

CentOS7 编译安装最新的Linux Kernel 6.0 rc3

哪个男孩不想手动编译一份自己的内核呢&#xff1f;安装编译环境 CentOS7安装必要的包 yum groupinstall "Development Tools" -y && yum install openssl-devel -y && yum install rpm-build redhat-rpm-config asciidoc hmaccalc perl-ExtUtils-…

Java核心技术卷Ⅰ-第四章对象和类

重点 1.使用预定义类 2.方法参数 3.对象构造 4.包 5.类设计技巧 1.使用预定义类 一个源文件只能有一个公共类&#xff0c;可以有任意数目的非公共类可以使用通配符调用Java编译器&#xff1a;javac Test*.java使用var声明局部变量就不用担心0、0L和0.0之间的区别&#xff0c;因…

找出链表中间结点的三种解法

初阶链表刷题注意&#xff01;&#xff01;&#xff01;学习的是解题的思维&#xff01; 找出链表的中间结点&#xff08;链接在末尾&#xff09; 解题思路 数组解法 由于链表不能通过下标访问对应的结点&#xff0c;所以我们将所有的结点存储在数组中&#xff0c;这样就可以通…

测试开发怎么学?

随着互联网行业的高速发展,快速高质量的产品版本迭代成为企业始终立于不败之地的迫切需求,而在短期迭代的快节奏中.传统测试工作面对更大压力,无法持续提供高效率高质量的人力支撑&#xff0c;所以越来越多的企业需要技术更为全面的测试开发工程师。 测试开发本质上属于测试,区…

【数据结构】二叉树链式结构的实现

&#x1f451;作者主页&#xff1a;进击的安度因 &#x1f3e0;学习社区&#xff1a;进击的安度因&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 文章目录一、二叉树的链式存储二、二叉树链式结构的实现结构设计手动构建二叉树前序遍历中序遍历…

游戏思考26:游戏服务器压力测试文档(最近在忙这个,这个会更新频繁,12/03未完待续)

文章目录一、压力测试关注点二、计算最耗时的加载操作1&#xff09;从数据库读取数据&#xff0c;对加载的类型进一步划分各种类型&#xff0c;计算最耗时操作2&#xff09;查看CPU随着在线人数的变化所占百分比3&#xff09;查看内存变化4&#xff09;备注一、压力测试关注点 …

【C语言字符串】一道题检验你的字符串学习情况

作者&#xff1a;匿名者Unit 目录 一.字符串引言1.字符串基础二.洛谷P5734详解1.字符串相关库函数&#xff08;1&#xff09; strcpy函数 &#xff08;2&#xff09; strcat函数 &#xff08;3&#xff09;strstr函数 2.题目讲解一.字符串引言 1.字符串基础 字符串通常以\0作为…