分析SpringBoot 底层机制【Tomcat 启动分析+Spring 容器初始化+Tomcat 如何关联Spring 容器之源码分析

news2024/11/25 9:54:30

目录

分析SpringBoot 底层机制【Tomcat 启动分析+Spring 容器初始化+Tomcat 如何关联Spring 容器之源码分析

搭建SpringBoot 底层机制开发环境

创建Maven 项目wyx-springboot

修改pom.xml , 导入相关依赖

创建MainApp.java

启动项目ok, 大家注意Tomcat 也启动了[这里思考, 是如何实现的?]

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

创建dog对象

创建Config.java类

MainApp.java, 看看容器中是否已经注入了dog 实例

底层机制分析:

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

创建HiController.java 

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

源码分析: SpringApplication.run()

1. 这里我们开始Debug SpringApplication.run()  

  2.SpringApplication.java : 创建返回 ConfigurableApplicationContext对象 

3. 还在SpringApplication.java

  5. ApplicationContextFactory.java

 6.然后返回到第3步骤然后我们在直接进去 refreshContext(context); 

 7. 直接进入refresh(context);

8.applicationContext.refresh();直接进入

9.然后直接进入super.refresh();到AbstractApplicationContext.java

10.直接进入onRefresh(); 

11.直接进入 createWebServer();

12.直接进入 this.webServer = factory.getWebServer(getSelfInitializer());

13.直接进入 getTomcatWebServer(tomcat);

14.直接进入TomcatWebServer(tomcat, getPort() >= 0, getShutdown());

15. 直接进入initialize();


分析SpringBoot 底层机制【Tomcat 启动分析+Spring 容器初始化+Tomcat 如何关联Spring 容器之源码分析

搭建SpringBoot 底层机制开发环境

创建Maven 项目wyx-springboot

步骤就不再展示了 在我的博客有

修改pom.xml , 导入相关依赖

    <!-- 导入springboot 父工程,规定的写法-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
    </parent>
    <!-- 导入web 项目场景启动器,会自动导入和web 开发相关依赖,非常方便-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

创建MainApp.java

@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动SpringBoot 应用程序
        ConfigurableApplicationContext run =
                SpringApplication.run(MainApp.class, args);
    }
}

启动项目ok, 大家注意Tomcat 也启动了[这里思考, 是如何实现的?]

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

创建dog对象

public class Dog {
}

创建Config.java类

@Configuration
public class Config {
    /**
     * 1. 通过@Bean 的方式, 将new 出来的Bean 对象, 放入到Spring 容器
     * 2. 该bean 在Spring 容器的name 就是方法名
     * 3. 通过方法名, 可以得到new Dog()
     * @return
     */
    @Bean
    public Dog dog() {
        return new Dog();
    }
}

MainApp.java, 看看容器中是否已经注入了dog 实例

 

 

 

底层机制分析:

仍然是我们实现Spring 容器那一套机制IO/文件扫描+注解+反射+集合+映射, 提示: 回去看博客-"实现Spring 底层机制程序" ,

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

创建HiController.java 

@RestController
public class HiController {
    @RequestMapping("/hi")
    public String hi() {
        System.out.println("hi i am HiController");
        return "hi i am HiController";
    }
}

        

 

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

源码分析: SpringApplication.run()

1、Debug SpringApplication.run(MainApp.class, args) 看看SpringBoot 是如何启动Tomcat 的.
2、我们的Debug 目标: 紧抓一条线, 就是看到tomcat 被启动的代码. 比如tomcat.start()

1. 这里我们开始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

1.先进去创建容器

2.然后在进去刷新上下文

3. SpringApplication.java
         
           public ConfigurableApplicationContext run(String... args) {
          		StopWatch stopWatch = new StopWatch();
          		stopWatch.start();
          		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
          		ConfigurableApplicationContext context = null;
          		configureHeadlessProperty();
          		SpringApplicationRunListeners listeners = getRunListeners(args);
          		listeners.starting(bootstrapContext, this.mainApplicationClass);
          		try {
          			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
          			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
          			configureIgnoreBeanInfo(environment);
          			Banner printedBanner = printBanner(environment);
          			context = createApplicationContext(); //严重分析: 创建容器
          			context.setApplicationStartup(this.applicationStartup);
          			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
          			refreshContext(context); //严重分析: 刷新应用程序上下文,比如 初始化默认设置/注入相关Bean/启动tomcat
          			afterRefresh(context, applicationArguments);
          			stopWatch.stop();
          			if (this.logStartupInfo) {
          				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
                                 }
          			listeners.started(context);
          			callRunners(context, applicationArguments); 		}
          		catch (Throwable ex) {
          			handleRunFailure(context, ex, listeners);
          			throw new IllegalStateException(ex);
          		}
         
          		try {
          			listeners.running(context);
          		}
          		catch (Throwable ex) {
          			handleRunFailure(context, ex, null);
          			throw new IllegalStateException(ex);
          		}
          		return context;
          	}

4. SpringApplication.java : 容器类型很多,会根据你的this.webApplicationType创建对应的容器默认 this.webApplicationType 是 SERVLET 也就是web容器/可以处理servlet

4. SpringApplication.java : 容器类型很多,会根据你的this.webApplicationType创建对应的容器
          	默认 this.webApplicationType 是 SERVLET 也就是web容器/可以处理servlet
          	protected ConfigurableApplicationContext createApplicationContext() {
          		return this.applicationContextFactory.create(this.webApplicationType);
                 }

 这里我们还是就直接进入

  5. ApplicationContextFactory.java

 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 ex) {
          			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
          					+ "you may need a custom ApplicationContextFactory", ex);
          		}
          	};

 6.然后返回到第3步骤然后我们在直接进去 refreshContext(context); 

6. SpringApplication.java
          	private void refreshContext(ConfigurableApplicationContext context) {
          		if (this.registerShutdownHook) {
          			shutdownHook.registerApplicationContext(context);
                         }
          		refresh(context); //严重分析,真正执行相关任务
           }

 7. 直接进入refresh(context);

7. SpringApplication.java
           protected void refresh(ConfigurableApplicationContext applicationContext) {
          		applicationContext.refresh();
             }

8.applicationContext.refresh();直接进入

8. ServletWebServerApplicationContext.java
           @Override
                 public final void refresh() throws BeansException, IllegalStateException {
          		try {
          			super.refresh();//分析这个方法
                 }
          		catch (RuntimeException ex) {
          			WebServer webServer = this.webServer;
          			if (webServer != null) {
          				webServer.stop();
                     }
          			throw ex;
                 }
             }

9.然后直接进入super.refresh();到AbstractApplicationContext.java

 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.直接进入onRefresh(); 

10. ServletWebServerApplicationContext.java
           @Override
          	protected void onRefresh() {
          		super.onRefresh();
          		try {
          			createWebServer();//看到胜利的曙光,创建webserver 可以理解成会创建指定web服务-Tomcat
                         }
          		catch (Throwable ex) {
          			throw new ApplicationContextException("Unable to start web server", ex);
                 }     	
}

11.直接进入 createWebServer();

11. ServletWebServerApplicationContext.java
         
            private void createWebServer() {
          		WebServer webServer = this.webServer;
          		ServletContext servletContext = getServletContext();
          		if (webServer == null && servletContext == null) {
          			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
          			ServletWebServerFactory factory = getWebServerFactory();
          			createWebServer.tag("factory", factory.getClass().toString());
          			this.webServer = factory.getWebServer(getSelfInitializer());//严重分析,使用TomcatServletWebServerFactory 创建一个TomcatWebServer
          			createWebServer.end();
          			getBeanFactory().registerSingleton("webServerGracefulShutdown",
          					new WebServerGracefulShutdownLifecycle(this.webServer));
          			getBeanFactory().registerSingleton("webServerStartStop",
          					new WebServerStartStopLifecycle(this, this.webServer));
                         }
          		else if (servletContext != null) {
          			try {
          				getSelfInitializer().onStartup(servletContext);
                     }
          			catch (ServletException ex) {
          				throw new ApplicationContextException("Cannot initialize servlet context", ex);
                     }
                 }
          		initPropertySources();     	}

12.直接进入 this.webServer = factory.getWebServer(getSelfInitializer());

12. TomcatServletWebServerFactory.java 会创建Tomcat 并启动Tomcat
         
                 @Override
             public WebServer getWebServer(ServletContextInitializer... initializers) {
          		if (this.disableMBeanRegistry) {
          			Registry.disableRegistry();
                 }
          		Tomcat tomcat = new Tomcat();//创建了Tomcat对象
          		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
          	    //做了一系列的设置
          		tomcat.setBaseDir(baseDir.getAbsolutePath());
         
          		Connector connector = new Connector(this.protocol);
          		connector.setThrowOnFailure(true);
          		tomcat.getService().addConnector(connector);
          		customizeConnector(connector);
          		tomcat.setConnector(connector);
          		tomcat.getHost().setAutoDeploy(false);
          		configureEngine(tomcat.getEngine());
          		for (Connector additionalConnector : this.additionalTomcatConnectors) {
          			tomcat.getService().addConnector(additionalConnector);
                 }
          		prepareContext(tomcat.getHost(), initializers);
          		return getTomcatWebServer(tomcat); //严重分析该方法.
             }

13.直接进入 getTomcatWebServer(tomcat);

13. TomcatServletWebServerFactory.java , 这里做了校验创建 TomcatWebServer
             protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
          		return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
                 }

14.直接进入TomcatWebServer(tomcat, getPort() >= 0, getShutdown());

14. TomcatServletWebServerFactory.java
             public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
          		Assert.notNull(tomcat, "Tomcat Server must not be null");
          		this.tomcat = tomcat;
          		this.autoStart = autoStart;
          		this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
          		initialize();//分析这个方法.
                 }

15. 直接进入initialize();

 15.TomcatServletWebServerFactory.java
         
             private void initialize() throws WebServerException {
          		logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
          		synchronized (this.monitor) {
          			try {
          				addInstanceIdToEngineName();
         
          				Context context = findContext();
          				context.addLifecycleListener((event) -> {
          					if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
          						// Remove service connectors so that protocol binding doesn't
          						// happen when the service is started.
          						removeServiceConnectors();
                                                 }                 				});
         
          				// Start the server to trigger initialization listeners
          				this.tomcat.start(); //启动Tomcat
         
          				// We can re-throw failure exception directly in the main thread
          				rethrowDeferredStartupExceptions();
         
          				try {
          					ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
                         }
          				catch (NamingException ex) {
          					// Naming is not enabled. Continue
                         }
         
          				// Unlike Jetty, all Tomcat threads are daemon threads. We create a
          				// blocking non-daemon to stop immediate shutdown
          				startDaemonAwaitThread();
                     }
          			catch (Exception ex) {
          				stopSilently();
          				destroySilently();
          				throw new WebServerException("Unable to start embedded Tomcat", ex);
                     }
                 }
             }
         

到处我们就全部debug到了下面我就就自己实现

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

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

相关文章

机器学习期末复习 BP神经网络的推导,4X4X3,激活函数变为Logistic函数,其他不变

刚写完了bp神经网络的实验课代码&#xff0c;对这个比较熟悉&#xff08;后面给出实现代码&#xff09; Logistic函数也就是sigmod函数&#xff0c;表达式是这样的&#xff1a; def sigmod(x):return 1/(1math.exp(-x)) sigmod函数是隐层和输出层的激活函数&#xff08;sigmo…

如何本地搭建Plex私人影音云盘教程,实现Plex家庭影音中心,打造超级多媒体中心

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 转发自CSDN远程穿透的文章&#xff1a;免费搭建Plex家庭影音中心 - 打造超级多媒体中心【公网远程访问…

WEBPACK、VITE 常用配置(对照)及迁移指南

文中 Webpack 版本为 5.x&#xff0c;Vite 版本为 4.3.x webpack 是新一代构建工具里面的老大哥了&#xff0c;从 2013 年发布已经持续升级 10 年&#xff0c;形成完备的生态环境。vite 则是下一代前端开发与构建工具&#xff0c;2019年发布&#xff0c;最新发布版本 4.3.3&…

文件操作安全之-文件上传告警运营篇

本文从文件上传的定义&#xff0c;文件上传的IDS规则&#xff0c;文件上传的示例&#xff0c;文件上传的告警研判&#xff0c;文件上传的处置建议等几个方面阐述如何通过文件上传类型的告警的线索&#xff0c;开展日常安全运营工作&#xff0c;从而挖掘有意义的安全事件。 文件…

rtl仿真器-iverilog icarus安装和测试

Icarus Verilog是一个轻量、免费、开源的Verilog编译器&#xff0c;基于C实现&#xff0c;开发者是 Stephen Williams &#xff0c;遵循 GNU GPL license 许可证&#xff0c;安装文件中已经包含 GTKWave支持Verilog/VHDL文件的编译和仿真&#xff0c;命令行操作方式&#xff0c…

C语言函数大全-- _w 开头的函数(1)

C语言函数大全 本篇介绍C语言函数大全-- _w 开头的函数 1. _waccess 1.1 函数说明 函数声明函数功能int _waccess(const wchar_t* path, int mode);用于测试文件或目录是否存在&#xff0c;并检查程序是否具有对它们的访问权限 参数&#xff1a; path &#xff1a; 待测试的…

Elasticsearch(三)

Elasticsearch(三) 数据聚合 聚合的分类 文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html 聚合可以实现对文档数据的统计、分析、运算。聚合常见的有三类&#xff1a; 桶聚合&#xff1a;用来对文档做分组 Te…

【P22】JMeter 调试后置处理程序(Debug PostProcessor)

&#xff08;1&#xff09;、测试计划右键 <<< 添加 <<< 线程&#xff08;用户&#xff09;<<< 线程组 默认参数即可 &#xff08;2&#xff09;、线程组右键 <<< 添加 <<< 取样器 <<< 调试取样器 默认参数即可 &…

SQL复习(一)——安装

1 mysql卸载 reference&#xff1a;https://blog.csdn.net/m0_67392273/article/details/126066580 Step1:停止MySql服务 在卸载之前&#xff0c;先停止MySQL8.0的服务 搜索“服务”&#xff0c;找到“MySQL”&#xff0c;右键点击选择“停止” Step2&#xff1a;软件的卸…

Unittest自动化测试之unittestunittest_生成测试报告

unittest_生成测试报告 测试报告为测试结果的统计即展示&#xff0c;是自动化测试不可或缺的一部分&#xff0c;利用unittest 可以生成测试报告 方式一、使用第三方 HTMLTestRunner 执行测试用例集&#xff0c;生成网页版测试报告&#xff08;推荐&#xff09; HTMLTestRunn…

5年软测经验去面试25k测试岗,看到这样的面试题我还是心虚了....

我是着急忙慌的准备简历——5年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;5年测试经验起码能要个25K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&#xff0c;自信满满去面试&#…

系统掌握入河排污口设置论证技术、方法及报告编制框架

在短时间内较系统的掌握入河排污口设置论证技术、方法及报告编制框架&#xff0c;学习内容以城镇生活污水厂、造纸项目、石化项目、制药项目案例为线索&#xff0c;系统讲解入河排污口设置论证报告书编制过程&#xff0c;并以水质模型为手段&#xff0c;讲解水质影响预测模型的…

Voice Control for ChatGPT 沉浸式的与ChatGPT进行交流学习。

Voice Control for ChatGPT 日常生活中&#xff0c;我们与亲人朋友沟通交流一般都是喜欢语音的形式来完成的&#xff0c;毕竟相对于文字来说语音就不会显的那么的苍白无力&#xff0c;同时最大的好处就是能解放我们的双手吧&#xff0c;能更快实现两者间的对话&#xff0c;沟通…

华为OD机试真题 Java 实现【简单的自动曝光】【2023Q1 100分】

一、题目描述 一个图像有 n 个像素点&#xff0c;存储在一个长度为 n 的数组 img 里&#xff0c;每个像素点的取值范围[0,255]的正整数。 请你给图像每个像素点值加上一个整k(可以是负数)&#xff0c;得到新图 newlmg&#xff0c;使得新图 newlmg 的所有像素平均值最接近中位…

响应式设计和移动端优化:如何实现页面在不同设备上的适配和优化

章节一&#xff1a;介绍响应式设计和移动端优化 响应式设计是一种使网页能够自适应不同设备和屏幕尺寸的设计方法。它通过使用流式网格布局、媒体查询和弹性图片等技术&#xff0c;使得网页能够在不同分辨率和设备上呈现出最佳的布局和用户体验。 移动端优化则是针对移动设备…

青训营 x 训练营结营测试题目(前端方向)

文章目录 &#x1f4cb;前言&#x1f3af;选择题&#xff08;含多选&#xff09;&#x1f4dd;最后 &#x1f4cb;前言 这篇文章的内容是23年6月青训营 x 训练营结营题目&#xff0c;题目一共有25题&#xff0c;题目类型为选择题&#xff0c;包括了单选题和多选题&#xff0c;…

WiFi(Wireless Fidelity)基础(十二)

目录 一、基本介绍&#xff08;Introduction&#xff09; 二、进化发展&#xff08;Evolution&#xff09; 三、PHY帧&#xff08;&#xff08;PHY Frame &#xff09; 四、MAC帧&#xff08;MAC Frame &#xff09; 五、协议&#xff08;Protocol&#xff09; 六、安全&#x…

VHDL直流电机模糊控制器的设计与实现

在直流电机控制策略方面,属于智能控制理论的模糊控制其突出优点在于它不依赖于被控对象的模型,因此本设计尝试将模糊控制理论应用于直流电机转速控制,并将模糊控制器实现于FPGA(Field Programmable Gate Array)芯片上。在实现方法上本设计采用模糊查表控制法实现模糊控制器…

【C++】-static在类和对象中的作用和细节(下)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 文章目录 前言 前言 今天我们来讲一个static对类的对象的作用…