系列文章目录

手写SpringBoot(一)之简易版SpringBoot手写SpringBoot(二)之动态切换Servlet容器手写SpringBoot(三)之自动配置手写SpringBoot(四)之bean动态加载手写SpringBoot(五)之整合AOP

整个章节代码,在my-spring-boot模块下

手写SpringBoot(一)之简易版SpringBoot

  1. 添加依赖
<?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>
    <parent>
        <groupId>cn.axj</groupId>
        <artifactId>spring-boot-base</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>my-spring-boot</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </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>

    </dependencies>

</project>
  1. 启动Spring容器
  • 定义MySpringBootApplication标识注解,对应SpringBootApplication
package cn.axj.springboot.my.annnotation;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
public @interface MySpringBootApplication {
}

Configuration 注解表明该注解标注的类是一个配置类,在AnnotationConfigApplication 里面会解析这个类,并加载相应的容器bean

CompontScan 注解定义Configuration配置类下的扫描路径,如果不传,默认扫描标注类的包名。所以SpringBoot默认会扫描Application类下的当前包以及子包路径。

  • 定义MySpringApplication类,对应SpringApplication
package cn.axj.springboot.my.boot;

import cn.axj.springboot.my.web.container.WebContainer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;


public class MySpringApplication {

    public static void run(Class<?> clazz,String[] args) {
        //启动Spring容器
        AnnotationConfigWebApplicationContext annotationConfigApplicationContext = new AnnotationConfigWebApplicationContext();
        annotationConfigApplicationContext.register(clazz);
        annotationConfigApplicationContext.refresh();
        //启动tomcat容器
        WebContainer.startContainer(annotationConfigApplicationContext);
    }
}
  • register(clazz)通过传入的class对象扫描步骤二中Configuration和ComponentScan定义的路径地址,扫描组件注入到容器中。
  • 这里由于MySpringBootApplication注解是一个组合注解,包括@Configuration和@ComponentScan,Spring在获取到@MySpringBootApplication标注的类,会默认将该类作为配置类,所以这个@MySpringBootApplication不一定非得加到Application类上,可以专门定义一个Configuration类来标注,但是需要将该类Class作为参数传给MySpringApplication.run方法中。
  • 由于@Component默认会扫描被该注解标注的类的当前包路径作为默认扫描路径。所以@MySpringBootApplication标注的类的包路径需要注意。
  1. 启动tomcat
    启动tomcat
    配置DispatcherServlet
package cn.axj.springboot.my.web.container;

import org.apache.catalina.*;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public abstract class WebContainer{

    public static void startContainer(WebApplicationContext webApplicationContext){
        System.out.println("启动Web容器");
        Tomcat tomcat = new Tomcat();

        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");

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

        StandardEngine 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);


        //配置dispatcherServlet,Springmvc专属
        tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet(webApplicationContext));
        context.addServletMappingDecoded("/*","dispatcher");


        try {
            tomcat.start();
        } catch (LifecycleException e) {
            throw new RuntimeException(e);
        }
    }
}

至此,一个简易版的SpringBoot就完成了。

整个结构如下图所示

spring boot怎么给程序制作心跳_apache

下面进行测试,新建一个user-service模块

  1. 引入自己写的springboot依赖
<?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>
    <parent>
        <groupId>cn.axj</groupId>
        <artifactId>spring-boot-base</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>user-service</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>cn.axj</groupId>
            <artifactId>my-spring-boot</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  1. 在cn.axj.user下面创建UserApplication
package cn.axj.user;

import cn.axj.springboot.my.annnotation.MySpringBootApplication;
import cn.axj.springboot.my.boot.MySpringApplication;

@MySpringBootApplication
public class UserApplication {

    public static void main(String[] args) {
        MySpringApplication.run(UserApplication.class, args);
    }
}
  1. 新建controller层TestController
package cn.axj.user.controller;

import cn.axj.user.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class TestController {


    @Resource
    private UserService userService;

    @GetMapping("/test")
    public String test(){
        return userService.test();
    }
}
  1. 新建service层UserService
package cn.axj.user.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public String test(){
        return "hello";
    }
}
  1. 启动main方法
启动Web容器
三月 27, 2024 5:55:51 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
三月 27, 2024 5:55:51 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
三月 27, 2024 5:55:51 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.75]
三月 27, 2024 5:55:52 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [322] milliseconds.
三月 27, 2024 5:55:52 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
三月 27, 2024 5:56:07 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring DispatcherServlet 'dispatcher'
三月 27, 2024 5:56:07 下午 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: Initializing Servlet 'dispatcher'
三月 27, 2024 5:56:08 下午 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: Completed initialization in 443 ms
三月 27, 2024 5:56:08 下午 org.springframework.web.servlet.DispatcherServlet noHandlerFound
警告: No mapping for GET /
三月 27, 2024 5:56:08 下午 org.springframework.web.servlet.DispatcherServlet noHandlerFound
警告: No mapping for GET /
三月 27, 2024 5:56:08 下午 org.springframework.web.servlet.DispatcherServlet noHandlerFound
警告: No mapping for GET /favicon.ico

至此项目启动完成

  1. 打开浏览器,访问localhost:8080/test,看到返回test字符串,代表成功

当我们想将tomcat换成jetty或者是underTow容器怎么实现呢?