springboot是如何工作的

news2024/9/25 11:11:53

一、前言

现在java后端开发框架比较多的使用springboot框架,springboot是在以前的springMVC进行封装和优化,最大的特点是简化了配置和内置Tomcat。本节通过阅读源码理解springboot是如何工作的。

二、springboot是如何工作的

1、从启动类开始

/**
  *服务启动类
  * @author: 
  * @Description:
  * @Company: 
  * @date: 
  */
@SpringBootApplication(scanBasePackages = {"cn.xxx.common","cn.xxx.admin.*","cn.xxx.interceptor.*"})
@EnableEurekaClient
@EnableApolloConfig
@EnableFeignClients(basePackages = {"cn.xxx.interceptor.*"})
@EnableDiscoveryClient
@MapperScan("cn.xxx.admin.dao")
@EnableSwagger2
@EnableTransactionManagement 
public class BaseAdminApplication {
	
	public static void main(String[] args) {
		SpringApplication.run(BaseAdminApplication.class,args);
	}

}

从代码上可以看出spring通过main方法启动,关键代码是这一句:SpringApplication.run(BaseAdminApplication.class,args);

和注解 @SpringBootApplication(scanBasePackages = {"cn.xxx.common","cn.xxx.admin.*","cn.xxx.interceptor.*"})

通过调用SpringApplication的run方法

	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}

可以看出传入的参数是 类  BaseAdminApplication.class

我们平时的方法很少参数传入一个类,这里传入一个类,就是为了获取这个类的属性,就是它上面的注解之类的

这里就要理解一下java的反射。

接着往下看  run(new Class<?>[] { primarySource }, args);

调用的run方法传入的是 类的数组  Class<?>[] { primarySource },数组中的元素是 BaseAdminApplication.class

继续往下调用

	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

这一段东西又怎么理解?

 new SpringApplication(primarySources).run(args);

这个是构造函数SpringApplication(primarySources),就是初始化出SpringApplication的一个实例对象,它传的值就是 BaseAdminApplication.class ,然后调用run的方法。

先看构成函数里都进行那些初始化

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

这里其实就是封装了配置信息

接下来看看如何运行配置文件和上下文信息

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		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);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

这段代码还是很复杂的,因为里面嵌套了很多模块和方法,它表示的就是如何处理配置信息和上下文。

三、扩展,java的反射

Java中的反射机制是指在运行时动态地获取一个类的信息,包括类的方法、属性、构造函数等,而不需要事先知道这个类的具体实现。通过反射机制,可以在程序运行时获取类的信息,并且可以在运行时调用类的方法、创建对象等。

反射机制主要包含以下几个核心类:

一:Class类:表示一个类的类型,可以通过它获取类的构造函数、方法、字段等信息。Class类是反射机制的核心类之一。它代表了一个类的类型,可以用来获取该类的构造函数、方法、字段等信息,也可以用来创建该类的对象。以下是Class类的一些常用方法:

  1. forName(String className):根据类的全限定名获取对应的Class对象。

  2. newInstance():创建该类的一个实例对象。

  3. getConstructor(Class<?>... parameterTypes):获取该类的指定构造函数。

  4. getDeclaredConstructor(Class<?>... parameterTypes):获取该类的指定构造函数,不考虑其访问权限。

  5. getMethod(String name, Class<?>... parameterTypes):获取该类的指定公共方法。

  6. getDeclaredMethod(String name, Class<?>... parameterTypes):获取该类的指定方法,不考虑其访问权限。

  7. getField(String name):获取该类的指定公共字段。

  8. getDeclaredField(String name):获取该类的指定字段,不考虑其访问权限。

在使用反射机制时,通常需要先获取对应的Class对象,然后再通过该对象获取需要的信息或者创建对象。

二:Constructor类:表示一个类的构造函数,可以通过它创建对象。在Java反射机制中,Constructor类表示一个类的构造函数,可以用来创建该类的实例对象。以下是Constructor类的一些常用方法:

  1. newInstance(Object... initargs):使用指定的参数创建该构造函数所表示的类的新实例。

  2. getParameterTypes():获取该构造函数的参数类型。

  3. getModifiers():获取该构造函数的修饰符。

  4. isVarArgs():判断该构造函数是否支持可变参数。

  5. isAccessible():判断该构造函数是否可以被访问。

  6. setAccessible(boolean flag):设置该构造函数的可访问标志。

使用Constructor类可以通过反射机制来创建一个类的实例对象,可以方便地调用私有构造函数等。

三:Method类:表示一个类的方法,可以通过它调用类的方法。Method类是用于表示类或接口的方法的反射机制类。它包含有关方法名称,参数类型,返回类型,访问修饰符等信息的元数据。

使用Method类,可以在运行时动态地调用类的方法,而无需在编译时知道类的确切类型。可以使用以下方法之一获取Method对象:

1.getMethod(String name, Class<?>... parameterTypes):返回具有指定名称和参数类型的公共方法。

2.getDeclaredMethod(String name, Class<?>... parameterTypes):返回具有指定名称和参数类型的方法,无论是否为公共方法。

一旦获得了Method对象,就可以使用invoke()方法调用它来执行方法,需要提供目标对象和方法的参数。如果方法是静态的,则可以将目标对象设置为null。

四:Field类:表示一个类的字段,可以通过它获取和设置类的属性值。Field类代表类或接口的字段,即类或接口中的变量。Field类提供了访问和操作字段的方法,包括获取字段的名称、类型、修饰符、值等。

Field类是通过Java反射机制来实现的,反射机制是一种在运行时分析和操作类、接口、方法、字段等程序构件的机制。使用反射机制,可以在运行时获取一个类的信息,包括其方法、字段、注解、泛型类型等,并可以动态地创建对象、调用方法、访问字段等

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

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

相关文章

“探索Linux世界:从CentOS安装到常见命令使用“

目录 引言一、安装CentOS二、Linux的常见命令文件夹和目录操作命令文件编辑命令vi或vim编辑器命令模式编辑模式末行模式 总结 引言 在计算机领域&#xff0c;Linux作为一种强大而灵活的操作系统&#xff0c;在服务器、嵌入式设备和个人电脑等领域广泛应用。本文将引导您了解并…

如何将 ONLYOFFICE 桌面版编辑器 7.5 安装到 Red Hat、CentOS 及衍生产品上

使用桌面版的 ONLYOFFICE 在线编辑器&#xff0c;您可使用本地文件操作&#xff0c;无需保持互联网连接状态。 ONLYOFFICE 桌面编辑器是什么 ONLYOFFICE 桌面编辑器是一款全面的办公工具&#xff0c;提供了文本文档、电子表格、演示文稿、可填写表单和 PDF 查看和编辑功能。它…

六、【图像去水印】

文章目录 裁剪法移动复制法内容识别去水印色阶法去水印消失点法去水印反相混合法 裁剪法 处于边缘的水印&#xff0c;通过裁剪去除&#xff0c;如下图&#xff1a; 移动复制法 移动复制法适用于水印的背景这部分区域比较相似的情况下使用&#xff0c;如下图先使用矩形选区选中…

ICS TRIPLEX T9402数字输出模块

数字输入模块是产业自动化和掌握体系中的闭键组件&#xff0c;用于向外部装备发送数字输入旌旗灯号&#xff0c;通常用于掌握继电器、阀门、机电、灯光和其他数字装备。以下是数字输入模块的一些主要用处&#xff1a; 掌握履行器&#xff1a; 数字输入模块用于掌握履行器装备&a…

工作中的小tips:如何快速提取图片或者pdf上的文字,进行编辑?

工作中经常会碰到需要的材料是图片或者不能拷贝的pdf之类的情况&#xff0c;那么有没有办法快速从上面提取文字呢&#xff1f; 最近发现一个很好用的网站&#xff0c;百度翻译。首先说明一下&#xff0c;接下来的方法比较适合短一点的文字&#xff0c;像是大篇幅的那种不太适合…

0001net程序设计-net大学校园二手交易平台

文章目录 摘 要目 录系统设计开发环境 摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&…

滑动窗口限流算法实现一

固定算法 原理&#xff1a;固定算法是将时间线分隔成固定大小的时间窗口&#xff0c;每个窗口都会有个计数器&#xff0c;用来记录窗口时间范围内的请求总数&#xff0c;如果窗口的请求总数达到最大限定值&#xff0c;会认定流量超限。比如将窗口大小设为1分钟&#xff0c;每分…

怎么搭建一个蛋糕店小程序?

在当今的移动互联网时代&#xff0c;很多企业纷纷选择了小程序作为推广和销售的利器。对于蛋糕店来说&#xff0c;创建一个小程序可以提高品牌知名度&#xff0c;增加销售渠道。下面&#xff0c;我们以【乔拓云】第三方平台为例&#xff0c;来介绍一个完整蛋糕店小程序的制作流…

Java学习 5.Java-逻辑控制

逻辑控制 逻辑控制分为&#xff1a;选择语句、循环语句 一、if和switch选择语句 顺序中夹杂着循环&#xff0c;伴随着一次次的选择不断地成长 1.if语句 选择语句 单分支 if() 表达式; int a60;if(a60){System.out.println("a60");} 双分支 if(){ 表达式1&…

人工智能AI 全栈体系(九)

第一章 神经网络是如何实现的 如何用神经网络处理不等长文本的方法&#xff1f; 八、循环神经网络&#xff08;RNN: Recurrent Neural Network&#xff09; 处理不等长文本的神经网络 – 循环神经网络 RNN。 1. 从句子理解说起 上次讲了用词向量表示词&#xff0c;一句话也…

Vue Router:让你的应用路由起来!

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

uni-app:查询对象中字段为可变情况的子项

如上图&#xff0c;数据中aaa为可变项&#xff0c;需要查询其子项name的值 var test aaa var data {"no":1,"aaa": {"name":张三,"age": 20}, } console.log(data[test].name) 定义一个变量test&#xff0c;其值设置为aaa&#xff…

SENet: 强化深度卷积神经网络的自适应特征学习

SENet&#xff08;Squeeze-and-Excitation Network&#xff09;是一种革命性的深度卷积神经网络架构&#xff0c;旨在提高模型对图像特征的建模能力。它引入了自适应特征重新校准机制&#xff0c;通过学习性地调整通道间的重要性&#xff0c;提高了模型的性能&#xff0c;广泛用…

在Windows上 ciphey安装(详细版)

文章目录 前言 一、不想卸载原有的python版本&#xff1f; 二、安装步骤 1.安装python 2.创建虚拟环境vnev 3.在ciphey的虚拟环境中进行激活 4.安装ciphey 三、参数列表 总结 前言 提示&#xff1a;安装了好几次&#xff0c;但是都没安装成功&#xff0c;我使用了三个电脑p…

前后端分离问题 | 协调

CORS error 跨域问题--->找后端 报错&#xff1a;Access to XMLHttpRequest at http://xxx/Info?id5 from origin http://localhost:xxx has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource.

阿里DDD大佬:从0到1,带大家精通DDD

说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 谈谈你的DDD落地经验&#xff1f; 谈谈你对DDD的理解&#xff1…

【word小技巧】如何在方框中打√

1、新建一个word文档 2、点击“插入”–>“符号”–>“其他符号” 3、字体选择“wingdings 2”&#xff0c;然后就可以看到想要的符号了。选择之后&#xff0c;点击插入 4、完成插入

堆叠大陆Stacklands中文版:激发你的创意与策略,开启全新的建造体验

你是否曾经梦想过成为一个建筑师&#xff0c;创造自己的世界&#xff1f;或者向往那些无尽的策略游戏&#xff0c;在其中规划、建造并统治一切&#xff1f;现在&#xff0c;这个梦想已经触手可及&#xff0c;因为堆叠大陆Stacklands正等待你的探索&#xff01; 堆叠大陆Stackl…

【多线程面试题十六】、谈谈ReentrantLock的实现原理

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;谈谈ReentrantLock的实现…

pytorch:R-CNN的pytorch实现

pytorch&#xff1a;R-CNN的pytorch实现 仅作为学习记录&#xff0c;请谨慎参考&#xff0c;如果错误请评论指出。 参考文献&#xff1a;Rich Feature Hierarchies for Accurate Object Detection and Semantic Segmentation      https://blog.csdn.net/qq_41694024/cat…