SpringBoot(源码解析 + 实现底层机制)

文章目录

1.搭建SpringBoot底层机制开发环境

1.创建maven项目
2.使用Git管理项目(可以略过)
1.创建一个github存储库
2.克隆到本地,复制文件夹的内容
3.粘贴到idea项目文件夹,将其作为本地仓库与远程仓库关联
3.pom.xml 引入父工程和场景启动器
  • 其实父工程只是指定了引入依赖的默认版本
  • 真正的依赖是场景启动器来引入的
xml 复制代码
  <!--导入springboot父工程-->
  <parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.5.3</version>
  </parent>
  <dependencies>
    <!--配置maven项目场景启动器,自动导入和web相关的包-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
4.编写运行类
java 复制代码
package com.sun.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

    }
}
5.启动运行类,思考:tomcat怎么启动的?

2.@Configuration机制梳理

1.环境搭建
1.文件目录
2.Dog.java
java 复制代码
package com.sun.springboot.bean;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Dog {

}
3.Config.java 注入单例Dog对象
java 复制代码
package com.sun.springboot.config;

import com.sun.springboot.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Configuration //作为一个配置类
public class Config {

    @Bean //将单例bean:Dog注入容器
    public Dog dog() {
        return new Dog();
    }
}
4.MainApp.java测试是否能够获取bean
java 复制代码
package com.sun.springboot;

import com.sun.media.sound.SoftTuning;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        Object bean = ioc.getBean("dog");
        System.out.println(bean);
    }
}
5.成功获取
2.机制分析
1.简述
2.图解

3.SpringBoot是怎么启动Tomcat的?

1.环境搭建
1.文件目录
2.HiController.java
java 复制代码
package com.sun.springboot.controller;

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

/**
 * @author 孙显圣
 * @version 1.0
 */
@RestController //将所有方法的返回结果转换成json字符串并返回
public class HiController {
    @RequestMapping("/hi")
    public String hi() {
        return "hi sun HiController";
    }
}
3.测试访问
2.源码分析
1.需求分析
2.创建容器过程
1.run方法打断点
2.进入
3.进入
4.进入 SpringApplication
5.继续进入
6.放行到创建容器的那个方法
7.进入
8.继续进入
9.下一步
10.跳出回到createApplicationContext()方法
3.找到createWebServer()
1.打断点
2.放行,并查看目前的容器
3.进入并执行到refresh方法
4.进入
5.再进入
6.进入
7.放行到那个断点
8.进入
9.下一步,找到了createWebServer方法
4.启动Tomcat
1.进入
2.放行到断点并进入getWebServer
3.进入
4.直接跳出
5.放行到下一个断点,然后进入
6.进入,给initialize方法下断点
7.进入,给tomcat.start()下断点
8.直接放行,tomcat启动成功
9.回到afterRefresh方法(一直跳出),此时应用程序上下文已经刷新成功
10.查看目前的容器,完成初始化

4.SpringBoot(实现底层机制)

1.创建Tomcat并启动
1.排除pom.xml中的 spring-boot-starter-tomcat并引入指定版本的Tomcat
xml 复制代码
    <!--导入springboot父工程-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.5.3</version>
    </parent>
    <dependencies>
        <!--配置maven项目场景启动器,自动导入和web相关的包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--  因为要手动创建Tomcat并启动所以,排除spring-boot-starter-tomcat-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--
            引入指定版本的tomcat
            当需要引入自定义版本的tomcat时,需要排除spring-boot-starter-tomcat,否则会出现GenericServlet Not Found的提示
        -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>8.5.75</version>
        </dependency>
    </dependencies>
2.编写SunSpringApplication.java
1.文件目录
2.创建Tomcat对象,关联Spring容器并启动
java 复制代码
package com.sun.sunspringboot;


import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.autoconfigure.web.ServerProperties;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class SunSpringApplication {
    /**
     * 创建Tomcat对象,关联Spring容器并启动
     */
    public static void run() {
        try {
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(9090);
            tomcat.start();
            System.out.println("Tomcat在9090端口监听");
            tomcat.getServer().await(); //等待
        } catch (LifecycleException e) {
            throw new RuntimeException(e);
        }
    }
}
3.编写SunMainApp.java,启动Tomcat
java 复制代码
package com.sun.sunspringboot;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class SunMainApp {
    public static void main(String[] args) {
        SunSpringApplication.run();
    }
}
4.结果展示
2.创建Spring容器
1.文件目录
2.Monster.java
java 复制代码
package com.sun.sunspringboot.bean;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Monster {

}
3.SunConfig.java
java 复制代码
package com.sun.sunspringboot.config;

import com.sun.sunspringboot.bean.Monster;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Configuration //配置类
@ComponentScan("com.sun.sunspringboot") //指定要扫描的包
public class SunConfig {
    @Bean
    public Monster monster() {
        return new Monster(); //单例bean注入容器
    }
}
4.SunHiController.java
java 复制代码
package com.sun.sunspringboot.controller;

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

/**
 * @author 孙显圣
 * @version 1.0
 */
@RestController
public class SunHiController {
    @RequestMapping("/sunhi")
    public String hi() {
        return "hi, SunHiController";
    }
}
3.完成关联
1.文件目录
2.编写SunWebApplicationInitializer的onStartup方法
  • 在Tomcat启动的时候会调用onStartup方法
  • 首先注册配置类,然后将中央控制器放到 servletContext
java 复制代码
package com.sun.sunspringboot;

import com.sun.sunspringboot.config.SunConfig;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

/**
 * 1.创建自己的Spring容器
 * 2.关联spring容器的配置
 * 3.完成spring容器配置的bean的创建,依赖注入
 * 4.完成中央控制器,并让其持有Spring容器
 * 5.这里的onStartup是Tomcat调用,并把ServletContext对象传入
 */
public class SunWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("start up");
        AnnotationConfigWebApplicationContext ac =
                new AnnotationConfigWebApplicationContext();

        //完成bean的创建和配置
        ac.register(SunConfig.class); //在ac中注册配置类
        ac.refresh();

        //创建中央控制器
        DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
        //将中央控制器放到servletContext
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", dispatcherServlet);
        //当tomcat启动时,加载中央控制器
        registration.setLoadOnStartup(1);
        //拦截请求,进行分发处理
        registration.addMapping("/");

    }
}
3.修改SunSpringApplication设置Tomcat的上下文路径
4.启动测试
1.报错
2.引入对应版本的jasper包即可
xml 复制代码
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper</artifactId>
            <version>8.5.75</version>
        </dependency>
3.重新启动
4.访问测试,成功返回结果
相关推荐
To_OC2 小时前
从一行入口代码啃透 NestJS:工厂模式、装饰器和依赖注入是怎么串起来的
后端·设计模式·nestjs
Python私教3 小时前
多个项目怎么安全合并?先适配,再切换
后端·python·架构
2601_963870203 小时前
【计算机毕业设计】基于Spring Boot的专科医院医疗管理系统
java·spring boot·课程设计
Bingo_BIG3 小时前
Java Spring 批量修改,实体、接口、方法的定义
java·spring
画中有画4 小时前
软件架构中质量属性(性能、安全、可扩展性)的权衡设计
java·运维·安全
Shaoxi Zhang4 小时前
JAVA学习笔记035——对象和JSON格式
java·笔记·学习
赵丙双4 小时前
CountDownLatch 源码分析
java·aqs·countdownlatch
Python私教4 小时前
从表格到管理系统:别先写页面,先补齐权限、流程和审计
数据库·后端·架构
余额瞒着我当琳4 小时前
C++--深拷贝三件套 + swap + 写时拷贝 + vector 扩容 + reserve
java·开发语言·c++
thefool1122664 小时前
翻转二叉树
java