springboot系列五: springboot底层机制实现 上

在这里插入图片描述


⬅️ 上一篇: springboot系列四: sprintboot容器功能


🎉 欢迎来到 springboot系列五: springboot底层机制实现 上 🎉

在本篇文章中,我们将深入探讨 Spring Boot 的底层机制。通过理解这些底层机制,您可以更好地掌握 Spring Boot 的工作原理,并在项目中应用这些知识。


🔧 本篇需要用到的项目: zzw-springboot项目


搭建SpringBoot底层机制开发环境

1.创建 Maven 项目 zzw-springboot, 参考springboot快速入门
在这里插入图片描述

2.在pom.xml引入SpringBoot父工程和web项目场景启动器

<?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.zzw</groupId>
    <artifactId>quickStart</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <!--导入springboot父工程-规定写法[在mybatis中讲过]-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.5.3</version>
    </parent>

    <!--导入web项目场景启动器: 会自动导入和web开发相关的所有依赖[库/jar]
    后面还会说明spring-boot-starter-web 到底引入哪些相关依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

3.创建com.zzw.springboot.MainApp.java SpringBoot引用主程序

/**
 * @SpringBootApplication: 表示这是一个springboot引用/项目
 */
@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动springboot应用程序/项目
        //提示问题:当我们执行run方法时,怎么就启动了我们的内置的Tomcat?
        //在分析run方法底层机制的基础上, 我们自己尝试实现
        ApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);
    }
}

4.启动项目 ok, 大家注意Tomcat也启动了.[这里请同学们先思考, 是如何实现的?]
在这里插入图片描述

@Configuration+@Bean会发生什么,并分析机制

1.创建D:\idea_project\zzw_springboot\zzw-springboot\src\main\java\com\zzw\springboot\bean\Dog.java

public class Dog {}

2.创建com.zzw.springboot.config

/**
 * @Configuration:指明当前类是一个配置类;充当Spring容器/Spring配置文件
 * 如果该配置类, 在springboot扫描的包/子包下, 会被注入到Spring容器中
 * 在该类中, 可以通过@Bean 来注入其它的组件
 */
@Configuration
public class Config {
    /**
     * 1.通过@Bean的方式, 将new出来的Bean对象, 放入到Spring容器
     * 2.该bean在Spring容器的name/id 默认就是 方法名
     * 3.通过方法名, 可以得到注入到容器中的dog对象
     */
    @Bean
    public Dog dog() {
        return new Dog();
    }
}

3.修改com.zzw.springboot.MainApp.java, 看看容器中是否已经注入了 dog 实例

debug

在这里插入图片描述

ioc容器中已经注入了 dog 实例

在这里插入图片描述

@Configuration注解标注的配置类也会被实例化并被注入到Spring容器.

在这里插入图片描述

4.底层机制分析: 仍然是 我们实现Spring容器那一套机制 IO/文件扫描+注解+反射+集合+映射. 提示: 回去复习一下 实现Spring底层机制.

(1)快捷键查看ioc->singletonObjects->table列表 有多少元素? table右键->Customize Data Views->Enable alternative view for… 但是勾选上会少很多东西
在这里插入图片描述
这里是按照索引排序,无法按照字母排序。

在这里插入图片描述

(2)debug时元素按照字母排列

在这里插入图片描述
在这里插入图片描述

提出问题: SpringBoot 是怎么启动Tomcat, 并可以支持访问@Controller

1.创建com.zzw.springboot.controller.HiController
RestController解释手动实现Tomcat底层机制

/**
 * 1.因为 HiController 被 @RestController 标注, 所以就是一个控制器
 * 2.HiController 在扫描包/子包下,就会被注入到Spring容器
 */
@RestController
public class HiController {

    @RequestMapping("/hi")
    public String hi() {
        return "hi zzw HiController";
    }
}

2.完成测试, 浏览器输入 http://localhost:8080/hi
在这里插入图片描述

3.提出问题: SpringBoot 是怎么内嵌 Tomcat, 并启动Tomcat的? => 追踪源码

源码分析: SpringApplication.run()

1.Debug SpringApplication.run(MainApp.class, args); 看看SpringBoot 是如何启动Tomcat的.

2.我们的Debug目标: 紧抓一条线, 就是看到 tomcat 被启动的代码, 比如 tomcat.start().

3.源码如下

@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动springboot应用程序/项目
        //提示问题:当我们执行run方法时,怎么就启动了我们的内置的Tomcat?
        //在分析run方法底层机制的基础上, 我们自己尝试实现
        ApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);

        /**
         *  这里我们开始Debug SpringApplication.run();
         *  1.SpringApplication.java
         *   public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
         *      return run(new Class[]{primarySource}, args);
         *  }
         *  2.SpringApplication.java: 创建返回 ConfigurableApplicationContext(这是个接口)对象
         * public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
         *      return (new SpringApplication(primarySources)).run(args);
         *  }
         *  3.SpringApplication.java
         * public ConfigurableApplicationContext run(String... args) {
         *     StopWatch stopWatch = new StopWatch();
         *     stopWatch.start();
         *     DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
         *     ConfigurableApplicationContext context = null;
         *     this.configureHeadlessProperty();
         *     SpringApplicationRunListeners listeners = this.getRunListeners(args);
         *     listeners.starting(bootstrapContext, this.mainApplicationClass);
         *
         *     try {
         *         ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
         *         ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
         *         this.configureIgnoreBeanInfo(environment);
         *         Banner printedBanner = this.printBanner(environment);
         *         context = this.createApplicationContext();//严重分析: 创建容器
         *         context.setApplicationStartup(this.applicationStartup);
         *         this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
         *         this.refreshContext(context);//严重分析: 刷新应用程序上下文, 比如 初始化默认设置/注入相关bean/启动tomcat
         *         this.afterRefresh(context, applicationArguments);
         *         stopWatch.stop();
         *         if (this.logStartupInfo) {
         *             (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
         *         }
         *
         *         listeners.started(context);
         *         this.callRunners(context, applicationArguments);
         *     } catch (Throwable var10) {
         *         this.handleRunFailure(context, var10, listeners);
         *         throw new IllegalStateException(var10);
         *     }
         *
         *     try {
         *         listeners.running(context);
         *         return context;
         *     } catch (Throwable var9) {
         *         this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
         *         throw new IllegalStateException(var9);
         *     }
         * }
         * 4.SpringApplication.java: 容器类型很多, 会根据你的this.webApplicationType创建对应的容器
         * this.webApplicationType 默认是 Servlet, 也就是web容器, 可以处理servlet
         * protected ConfigurableApplicationContext createApplicationContext() {
         *     return this.applicationContextFactory.create(this.webApplicationType);
         * }
         * 5.ApplicationContextFactory.java
         *  ApplicationContextFactory DEFAULT = (webApplicationType) -> {
         *      try {
         *          switch(webApplicationType) {
         *          case SERVLET://默认进入到这个分支, 返回AnnotationConfigServletWebServerApplicationContext容器
         *              return new AnnotationConfigServletWebServerApplicationContext();
         *          case REACTIVE:
         *              return new AnnotationConfigReactiveWebServerApplicationContext();
         *          default:
         *              return new AnnotationConfigApplicationContext();
         *          }
         *      } catch (Exception var2) {
         *          throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
         *      }
         *  };
         *  6.SpringApplication.java
         *  private void refreshContext(ConfigurableApplicationContext context) {
         *      if (this.registerShutdownHook) {
         *          shutdownHook.registerApplicationContext(context);
         *      }
         *
         *      this.refresh(context);//严重分析, 真正执行相关任务
         *  }
         *  7.SpringApplication.java
         *  protected void refresh(ConfigurableApplicationContext applicationContext) {
         *     applicationContext.refresh();
         * }
         * 8.ServletWebServerApplicationContext.java
         * public final void refresh() throws BeansException, IllegalStateException {
         *     try {
         *         super.refresh();//分析这个方法
         *     } catch (RuntimeException var3) {
         *         WebServer webServer = this.webServer;
         *         if (webServer != null) {
         *             webServer.stop();
         *         }
         *
         *         throw var3;
         *     }
         * }
         * 9.AbstractApplicationContext.java
         * @Override
         * 	public void refresh() throws BeansException, IllegalStateException {
         * 		synchronized (this.startupShutdownMonitor) {
         * 			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
         *
         * 			// Prepare this context for refreshing.
         * 			prepareRefresh();
         *
         * 			// Tell the subclass to refresh the internal bean factory.
         * 			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
         *
         * 			// Prepare the bean factory for use in this context.
         * 			prepareBeanFactory(beanFactory);
         *
         * 			try {
         * 				// Allows post-processing of the bean factory in context subclasses.
         * 				postProcessBeanFactory(beanFactory);
         *
         * 				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         * 				// Invoke factory processors registered as beans in the context.
         * 				invokeBeanFactoryPostProcessors(beanFactory);
         *
         * 				// Register bean processors that intercept bean creation.
         * 				registerBeanPostProcessors(beanFactory);
         * 				beanPostProcess.end();
         *
         * 				// Initialize message source for this context.
         * 				initMessageSource();
         *
         * 				// Initialize event multicaster for this context.
         * 				initApplicationEventMulticaster();
         *
         * 				// Initialize other special beans in specific context subclasses.
         * 				onRefresh();//严重分析, 当父类完成通用的工作后, 再重新动态绑定机制回到子类
         *
         * 				// Check for listener beans and register them.
         * 				registerListeners();
         *
         * 				// Instantiate all remaining (non-lazy-init) singletons.
         * 				finishBeanFactoryInitialization(beanFactory);
         *
         * 				// Last step: publish corresponding event.
         * 				finishRefresh();
         * 			}
         *
         * 			catch (BeansException ex) {
         * 				if (logger.isWarnEnabled()) {
         * 					logger.warn("Exception encountered during context initialization - " +
         * 							"cancelling refresh attempt: " + ex);
         * 				}
         *
         * 				// Destroy already created singletons to avoid dangling resources.
         * 				destroyBeans();
         *
         * 				// Reset 'active' flag.
         * 				cancelRefresh(ex);
         *
         * 				// Propagate exception to caller.
         * 				throw ex;
         * 			}
         *
         * 			finally {
         * 				// Reset common introspection caches in Spring's core, since we
         * 				// might not ever need metadata for singleton beans anymore...
         * 				resetCommonCaches();
         * 				contextRefresh.end();
         * 			}
         * 		}
         * 	}
         * 	10.ServletWebServerApplicationContext.java
         *  protected void onRefresh() {
         *     super.onRefresh();
         *
         *     try {
         *         this.createWebServer();//看到胜利的曙光. 创建webserver 可以理解成会创建指定web服务-Tomcat
         *     } catch (Throwable var2) {
         *         throw new ApplicationContextException("Unable to start web server", var2);
         *     }
         * }
         * 11.ServletWebServerApplicationContext.java
         *  private void createWebServer() {
         *      WebServer webServer = this.webServer;
         *      ServletContext servletContext = this.getServletContext();
         *      if (webServer == null && servletContext == null) {
         *          StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
         *          ServletWebServerFactory factory = this.getWebServerFactory();
         *          createWebServer.tag("factory", factory.getClass().toString());
         *          this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});//严重分析, 使用TomcatServletWebServerFactory 创建一个TomcatWebServer
         *          createWebServer.end();
         *          this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
         *          this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
         *      } else if (servletContext != null) {
         *          try {
         *              this.getSelfInitializer().onStartup(servletContext);
         *          } catch (ServletException var5) {
         *              throw new ApplicationContextException("Cannot initialize servlet context", var5);
         *          }
         *      }
         *
         *      this.initPropertySources();
         *  }
         *  12.TomcatServletWebServerFactory.java: 会创建Tomcat, 并启动
         *  public WebServer getWebServer(ServletContextInitializer... initializers) {
         *     if (this.disableMBeanRegistry) {
         *         Registry.disableRegistry();
         *     }
         *
         *     Tomcat tomcat = new Tomcat();//创建了Tomcat对象
         *     File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
         *     //这里做了一系列配置
         *     tomcat.setBaseDir(baseDir.getAbsolutePath());
         *     Connector connector = new Connector(this.protocol);
         *     connector.setThrowOnFailure(true);
         *     tomcat.getService().addConnector(connector);
         *     this.customizeConnector(connector);
         *     tomcat.setConnector(connector);
         *     tomcat.getHost().setAutoDeploy(false);
         *     this.configureEngine(tomcat.getEngine());
         *     Iterator var5 = this.additionalTomcatConnectors.iterator();
         *
         *     while(var5.hasNext()) {
         *         Connector additionalConnector = (Connector)var5.next();
         *         tomcat.getService().addConnector(additionalConnector);
         *     }
         *
         *     this.prepareContext(tomcat.getHost(), initializers);
         *     return this.getTomcatWebServer(tomcat);//严重分析该方法.
         * }
         * 13.TomcatServletWebServerFactory.java
         * protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
         *     return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
         * }
         * 14.TomcatServletWebServerFactory.java
         * public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
         *     this.monitor = new Object();
         *     this.serviceConnectors = new HashMap();
         *     Assert.notNull(tomcat, "Tomcat Server must not be null");
         *     this.tomcat = tomcat;
         *     this.autoStart = autoStart;
         *     this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
         *     this.initialize();//分析这个方法
         * }
         * 15.TomcatServletWebServerFactory.java
         *  private void initialize() throws WebServerException {
         *     logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
         *     Object var1 = this.monitor;
         *     synchronized(this.monitor) {
         *         try {
         *             this.addInstanceIdToEngineName();
         *             Context context = this.findContext();
         *             context.addLifecycleListener((event) -> {
         *                 if (context.equals(event.getSource()) && "start".equals(event.getType())) {
         *                     this.removeServiceConnectors();
         *                 }
         *
         *             });
         *             this.tomcat.start();//启动Tomcat
         *             this.rethrowDeferredStartupExceptions();
         *
         *             try {
         *                 ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
         *             } catch (NamingException var5) {
         *                 ;
         *             }
         *
         *             this.startDaemonAwaitThread();
         *         } catch (Exception var6) {
         *             this.stopSilently();
         *             this.destroySilently();
         *             throw new WebServerException("Unable to start embedded Tomcat", var6);
         *         }
         *
         *     }
         * }
         */
        System.out.println("ok.");
    }
}

SpringBoot的debug流程

在这里插入图片描述

F7, Step Into
在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

webApplicationType类型可以在配置文件中修改

在这里插入图片描述

F7, Step Into

在这里插入图片描述

Shift+F8, Step Out

在这里插入图片描述

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

看看父类的类型

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

放行 Resume Problem

在这里插入图片描述

F7, Step Into

在这里插入图片描述

放行 Resume Problem
在这里插入图片描述

对容器进行估值

在这里插入图片描述


🔜 下一篇预告: springboot系列六: springboot底层机制实现 下


📚 目录导航 📚

  1. springboot系列一: springboot初步入门
  2. springboot系列二: sprintboot依赖管理
  3. springboot系列三: sprintboot自动配置
  4. springboot系列四: sprintboot容器功能
  5. springboot系列五: springboot底层机制实现 上
  6. springboot系列六: springboot底层机制实现 下
  7. springboot系列七: Lombok注解,Spring Initializr,yaml语法

💬 读者互动 💬
在探索 Spring Boot 底层机制的过程中,您有哪些收获或遇到过哪些挑战?欢迎在评论区留言,让我们一起讨论吧!😊


  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值