SpringBoot 源码解析2:启动流程

SpringBoot 之启动流程 加载应用程序上下文扫描应用程序中的所有组件自动配置应用程序环境启动嵌入式Web服务器在下面的章节中,我们将逐一分析这些步骤的源代码。在本文中,我们深入分析了 SpringBoot 应用程序的启动过程的源代码。我们了解了 SpringBoot 如何加载应用程序上下文、扫描应用程序中的所有组件、自动配置应用程序环境以及启动嵌入式Web服务器。这些步骤的源代码展示了 SpringBoot 如何简化应用程序的开发和部署。 阅读详情

1.启动方式

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

SpringBoot启动方式,这里就不多做说明了

2.@SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
	xxxxx
}
  1. 可以看到SpringBootApplication注解由三个注解标注,@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。
  2. 简要说明一下这三个注解的作用:
    2.1. SpringBootConfiguration由Configuration标注,而Configuration又是由Component标注,Component表明这个类要被Spring管理。同时Configuration注解还能对当前类进行代理。
    2.2. EnableAutoConfiguration是由@Import注解所标注,而Import注解的作用是告诉Spring容器需要注入哪些bean。
    2.3. ComponentScan是用来配置扫描Component资源的策略,包含策略和剔除策略,剔除策略优先及高。

3.SpringApplication

3.1 构造器SpringApplication

@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();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}
  1. 参数说明:resourceLoader写死null,primarySources为启动类MyApplication。
  2. 通过classLoader判断当前的WebApplicationType,这里返回的是WebApplicationType.SERVLET。
  3. 从spring.factories文件中拿到ApplicationContextInitializer和ApplicationListener。spring.factories文件解析可参考 SpringBoot 基础概念:SpringApplication#getSpringFactoriesInstances
  4. 推断出主类,通过RuntimeException的栈帧信息找到第一个"main"方法所属的类,也就是MyApplication。

3.2 SpringApplication#run

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		refreshContext(context);
		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, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
  1. 这是SpringBoot真正启动的总流程。
  2. 从spring.factories文件中获取SpringApplicationRunListener对应的类,通过参数类型为SpringApplication.class, String[].class的构造器实例化,其中值为当前的SpringApplication对象和启动参数args,封装在SpringApplicationRunListeners里。其实是实例化了EventPublishingRunListener,从名字上可知,它是用来分发事件的。
    在这里插入图片描述
  3. 调用SpringApplicationRunListeners#starting发布"正在启动"事件,事件为ApplicationStartingEvent。
  4. prepareEnvironment方法发布"环境准备"事件,由ConfigFileApplicationListener监听,然后解析配置文件(如yml、bootstrap、properties、xml等),将解析的信息存放到Environment里面。
  5. printBanner方法打印banner
  6. createApplicationContext创建ApplicationContext,判断的依据是webApplicationType。由于是Servlet类型的,创建的是AnnotationConfigServletWebServerApplicationContext。
  7. 获取异常报告事件监听器,在catch到异常监听failed。
  8. 准备applicationContext
  9. refreshContext(context)刷新容器
  10. listeners.started(context) 发布"已启动"事件
  11. 调用ApplicationRunner和CommandLineRunner
  12. listeners.running发送"running事件"

3.3 SpringApplication#run 中关键方法

3.1 SpringApplication#prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}
  1. getOrCreateEnvironment为Spring创建了环境StandardServletEnvironment,环境变量中有四个propertySources,servletContextInitParams、servletConfigInitParams、systemProperties、systemEnvironment,在Environment的propertySources中存放的是具体的配置信息。
  2. configureEnvironment方法为environment配置了转换器ConversionService,解析启动参数args保存到环境变量(保存在SimpleCommandLinePropertySource,其name为commandLineArgs)。解析启动参数args中的spring.profiles.active。
  3. ConfigurationPropertySources#attach,获取到name=configurationProperties的propertySource,如果与environment里面的propertySources不想同就remove。重新添加name=configurationProperties的propertySource,值为environment里面所有的propertySources。
  4. 发送environmentPrepared事件,ConfigFileApplicationListener监听到该事件,会对配置文件解析,下面会对ConfigFileApplicationListener进行解析。监听器原理可参考:SpringBoot 源码解析4:事件监听器
  5. 绑定环境变量,属性为spring.main,绑定对象为当前的SpringApplication。
  6. 如果是自定义environment(配置文件中配置spring.main.isCustomEnvironment),可自定义environment的类型。
3.1.1 环境准备监听器 ConfigFileApplicationListener
//EventPublishingRunListener#environmentPrepared
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
	this.initialMulticaster
			.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

//ConfigFileApplicationListener#onApplicationEvent
@Override
public void onApplicationEvent(ApplicationEvent event) {
	if (event instanceof ApplicationEnvironmentPreparedEvent) {
		onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
	}
	if (event instanceof ApplicationPreparedEvent) {
		onApplicationPreparedEvent(event);
	}
}

//ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
	List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
	postProcessors.add(this);
	AnnotationAwareOrderComparator.sort(postProcessors);
	for (EnvironmentPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
	}
}

可以看到,发布的是ApplicationEnvironmentPreparedEvent事件,所以会回调onApplicationEnvironmentPreparedEvent方法。
在onApplicationEnvironmentPreparedEvent方法中,加载了spring.factories文件中的所有EnvironmentPostProcessor,并且把当前对象放入到集合中,然后根据order排序,再回调postProcessEnvironment方法。

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
	RandomValuePropertySource.addToEnvironment(environment);
	new Loader(environment, resourceLoader).load();
}

先在systemEnvironment的propertySource后面增加random的propertySource,然后在通过Loader去加载。具体的加载逻辑在Loader里面。

3.1.2 加载配置文件 Loader

构造器

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
	this.environment = environment;
	this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
	this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
	this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
			getClass().getClassLoader());
}
  1. 保存了当前的环境
  2. 创建了占位符解析器placeholdersResolver ,${属性:默认属性值}
  3. 从spring.factories文件中获取了所有的属性资源加载器PropertySourceLoader。
    在这里插入图片描述
    其中PropertiesPropertySourceLoader负责加载properties和xml文件,YamlPropertySourceLoader负责加载yml和yaml文件
    在这里插入图片描述

在这里插入图片描述
配置文件加载原理请参考:SpringBoot 扩展篇:ConfigFileApplicationListener源码解析

3.2 SpringApplication#createApplicationContext

该方法创建了ApplicationContext

3.2.1 SpringApplication#createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

根据不同的webApplicationType创建不同的ApplicationContext,这里创建的是AnnotationConfigServletWebServerApplicationContext

3.2.2 AnnotationConfigServletWebServerApplicationContext构造器
public AnnotationConfigServletWebServerApplicationContext() {
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

从名字上来看AnnotationConfigServletWebServerApplicationContext是支持注解式的appicationContext。reader负责的是对BeanDefinition的注解进行解析,而scanner进行扫描(看哪些class需要生成BeanDifinition)。

3.2.3 org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}
  1. 在创建AnnotatedBeanDefinitionReader的同时,Spring还注册了一些及其重要的后置处理器,这些postProcessor及其重要,后面会一一解析其源码。
  2. ConfigurationClassPostProcessor:负责注解的解析,生成BeanDefinition,比如@Component、@ConponentScan、@Configuration、@Import等注解。
  3. AutowiredAnnotationBeanPostProcessor:解析@Autowired、@Value、@Inject(JSR)注解,初始化字段或调用方法。
  4. CommonAnnotationBeanPostProcessor:解析@Resource注解。
  5. EventListenerMethodProcessor、DefaultEventListenerFactory:对注解式事件监听器的支持EventListener。

3.3 SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}
  1. 对已经创建好的applicationContext进行准备和初始化。
  2. applyInitializers方法:负责对applicationContext初始化。在SpringApplication对象创建的时候,从spring.factories文件中配置的多个ApplicationContextInitializer,调用了initialize方法。可以addApplicationListener、registerSingleton、addBeanFactoryPostProcessor,甚至可以从环境变量context.initializer.classes中读取自定义的ApplicationContextInitializer进行回调(DelegatingApplicationContextInitializer)。
  3. 之前对SpringApplication对象绑定的spring.main.allowBeanDefinitionOverriding,对beanfactory设置了allowBeanDefinitionOverriding初始化。
  4. 创建了BeanDefinitionLoader,并且加载当前的source(MyApplication),注册BeanDenition。
  5. listeners.contextLoaded(context)方法不仅仅触发了监听器。还将当前的监听器add到ApplicationContext中,以便后续ApplicationContext容器刷新使用这些监听器。
public void contextLoaded(ConfigurableApplicationContext context) {
	for (ApplicationListener<?> listener : this.application.getListeners()) {
		if (listener instanceof ApplicationContextAware) {
			((ApplicationContextAware) listener).setApplicationContext(context);
		}
		context.addApplicationListener(listener);
	}
	this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

3.4 SpringApplication#refreshContext

负责对Spring容器的刷新,注册和实例化bean的核心逻辑

3.5 callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	List<Object> runners = new ArrayList<>();
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	AnnotationAwareOrderComparator.sort(runners);
	for (Object runner : new LinkedHashSet<>(runners)) {
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

回调ApplicationRunner和CommandLineRunner的run方法,参数为启动参数args,可通过Order控制回调顺序。Run方法的回调是在主线程完成的。

Spring Boot启动流程详解 Spring Boot是一个基于Spring框架的快速开发工具,它可以帮助我们快速搭建一个可运行的Spring应用。本文将详细介绍Spring Boot的启动流程,帮助大家更好地理解Spring Boot的工作原理。 阅读详情

相关推荐

SpringBoot-V2.1.0.RELEASE源码分析

#SpringBoot源码分析 基于2.1.0.RELEASE做的源码解析 ##1. 环境搭建 下载 登录github下载当前版本的源码,clone或打包都行 解压 解压下载的spring-boot-2.1.0.RELEASE.zip到D盘根目录,路径深度问题,放其他子文件夹报错; 编译 进入D:\spring-boot-2.1.0.RELEASE打开命令行窗口,执行maven编译命令,等待… mvn clean install -DskipTests IDEA导入 菜单 File

loongboys的博客 704

Springboot启动流程

一、SpringBoot启动的时候,会构造一个SpringApplication的实例,构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事: 1、把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数. 2、判断是否是web程序,并设置到webEnvironment的boolean属性中. 3、创建并初始化ApplicationInitializer,设置到initializers属性中 。 4、创建并初始化App

zsh2050的专栏 6万+

Spring Boot的启动流程

- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 创建springbootApplication对象 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - 1. 创建springbootApplication对象springboot容器初始化操作 2. 获取当前应用的启动类型。2.1 :通过判断当前classpath是否加载servlet类,返回servlet web启动方式。

流楚丶格念的博客 2万+

9千字长文带你了解SpringBoot启动过程–史上最详细 SpringBoot启动流程-图文并茂

9千字长文带你了解SpringBoot启动过程–史上最详细 SpringBoot启动流程-图文并茂

weixin_42113716的博客 1万+

Spring Boot 启动流程全解析:断点调试+源码逐行拆解(新手也能看懂)

关键断点位置构造方法、;调试快捷键F7(Step Into):进入方法内部(源码拆解核心快捷键);F8(Step Over):执行下一行,不进入方法;F9(Resume Program):跳到下一个断点;Alt+F8:计算表达式(比如查看的值);查看变量:调试时在Variables面板查看核心变量(如context),验证逻辑是否符合预期。初始化:推断应用类型、加载扩展组件;准备环境:加载配置文件、环境变量;创建上下文:根据应用类型创建核心容器;

2601_94871597的博客 200

Origin软件XRD全峰拟合保姆级教程:从数据导入到弱峰处理技巧

本文提供了一份Origin软件进行XRD全峰拟合的深度实战指南。文章重点解析了从数据导入预处理、基线锚点视觉化设置,到弱峰拟合的锁定策略与手动干预等核心技巧,旨在帮助用户避开常见错误,获得可靠、精确的拟合结果,从而有效服务于材料结构分析。

rgv2345678的博客 706

Alian解读SpringBoot 2.6.0 源码(三):启动流程分析之命令行参数解析

一、背景 1.1、run方法整体流程 1.2、本文解读范围 二、默认应用参数解析 2.1、接口ApplicationArguments 2.2、实现类DefaultApplicationArguments 2.2.1 实现类源码 2.2.2 Source类图 2.3、流程分析 2.3.1、初始化DefaultApplicationArguments 2.3.2、命令行参数解析 2.4、参数封装 2.5、实际演示 2.5.1 命令行参数设置图 2.5.2 测试及结果 结语

嘉禾嘉宁papa 5399

从零开始:YOLOv8车牌检测模型训练全流程实战

本文详细介绍了从零开始训练YOLOv8车牌检测模型的全流程实战指南。内容涵盖环境搭建、数据集收集与标注、模型配置与训练、评估测试及高级优化技巧。通过使用预训练模型和迁移学习,开发者可以高效构建精准的车牌检测系统,并掌握模型导出与部署的关键步骤。

weixin_29061041的博客 335

SpringBoot系列 启动流程

下面记录SpringBoot的启动流程

vonlinee的博客 1623

【智能教育实践】MOOPer数据集在个性化学习路径规划中的应用

本文探讨了如何利用MOOPer数据集实现从“千人一面”到“千人千面”的个性化学习路径规划。通过分析学习者与平台的交互数据(如练习、反馈、讨论)并结合知识图谱,系统能够动态诊断学生知识状态,并为其推荐最优学习序列。文章详细介绍了基于数据驱动的推荐系统核心技术,包括知识追踪、图谱关联挖掘及排序策略,旨在解决传统在线教育的僵化问题,提升学习效率与动力。

read5的博客 230

第4课 SiC MOSFET的动态特性——关断过程

本文分析了SiC MOSFET的关断过程,将其划分为四个阶段:栅源电容放电阶段(t6-t7)、米勒平台阶段(t7-t8)、电压过冲阶段(t8-t9)和换流结束阶段(t9-t10)。通过等效电路详细描述了各阶段的电压电流变化特点。同时探讨了MOSFET的极间电容特性,包括输入电容Ciss、输出电容Coss和反向转移电容Crss,分析了它们对器件开关速度、损耗及电压变化速率的影响。研究指出这些非线性电容会显著影响器件的动态性能。

嵌入式老牛的博客 1043

SpringBoot – 06 – SpringBoot 2.x 启动流程源码解析

本文基于 SpringBoot 2.3.4.RELEASE 版本进行分析 1、启动类 @SpringBootApplication public class SpringbootTestApplication { public static void main(String[] args) { SpringApplication.run(SpringbootTestApplication.class, args); } } 该类主要为项目启动提供入口,通过 main()

半日橙 402

香橙派rk3588的rknn多线程推理RTSP流服务性能优化与资源分配策略

本文深入探讨了香橙派RK3588平台上的RKNN多线程推理在RTSP流服务中的性能优化与资源分配策略。通过分析硬件架构、设计多线程推理流水线、实现NPU核心负载均衡及优化RGA内存管理,显著提升了RTSP视频流的处理帧率和降低了延迟,为边缘计算视频分析应用提供了实用的优化方案。

7up55的博客 653

SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析

先从@SpringBootApplication开始。 在启动流程章节中,我们讲述了SpringBoot2大致的启动步骤,并进行了源码详解。但是在刷新容器这块并未展开,refreshContext(context);简单的一行代码,背后却做了太多事情。所以为了不喧宾夺主,本篇也尽量选取和注解@SpringBootApplication有关的方法讲解。 1)springBoot启动类加载 首先加载...

u014513171的博客 382

从ISCXTor2016到CICIDS2017:手把手教你下载和使用UNB的网络安全数据集

本文详细介绍了UNB大学发布的ISCXTor2016和CICIDS2017等网络安全数据集的下载与使用方法,特别适合加密流量识别和网络行为分析研究。文章提供了多种高效获取路径、文件结构解析及实战分析示例,帮助研究者快速上手这些真实场景捕获的精细标注数据集。

weixin_42524945的博客 630

怎么在豆包里做生成式引擎优化(GEO)

本文系统介绍了豆包平台生成式引擎优化(GEO)的全套方法体系。文章首先解析了豆包与传统搜索引擎的核心差异,强调其多模态理解和上下文感知特性,并指出GEO需从关键词匹配转向用户意图动态解析。随后详细阐述了GEO优化的三大核心策略:用户意图解析技术、实时内容适配框架和权威信号强化方法,配以技术实现路径和案例说明。最后提出GEO与SEO融合的未来趋势,建议企业构建统一知识库,实现全渠道声誉管理。全文包含大量实操代码和工具链指导,为企业在AI时代的内容优化提供系统解决方案。

解锁AI流量新红利!🚀 GEO优化(生成引擎优化)助您掌控AI搜索,让AI成为您的品牌最佳代言人! 2371

一、【彻底精通Spring Boot2源码】 SpringApplication.run() 启动流程源码彻底剖析

       本文是对spring boot2 启动整个流程进行源码解析,也是我发表springboot系列的第一篇文章,解析的过程我会一行一行解读,网上很多的解析案例都是贴一段源码,然后说几句概况性的语句,看了之后也是丈二和尚 摸不到头脑,既然解析源码,我们就尽量彻底理解每一行是做什么的,有什么作用。   下面我们来看源码,走进启动模式; SpringApplication.run(Boo...

学而不思则罔,思而不学则殆! 1770

Unity接入抖音小程序侧边栏

Unity接入抖音小程序侧边栏功能实践总结 本文分享了Unity游戏接入抖音小程序侧边栏复访功能的实现过程。针对官方文档不清晰的问题,作者详细介绍了关键实现步骤:通过TT.CheckScene检测侧边栏可用性,利用OnShow事件监听判断用户是否从侧边栏进入,并提供了完整的UI交互代码示例。重点功能包括:检测宿主版本支持、区分侧边栏入口与非侧边栏入口的界面展示、实现跳转侧边栏场景等。文中附有官方文档链接和效果截图,为开发者提供了实用的接入参考方案。

类人_猿的博客 612

SpringBoot2 | SpringBoot启动流程源码分析(一)

概述: 前阵子看到了SpringCloud社区的一个开源项目,主要是对服务发现增强的功能。研究项目的时候发现代码简练,优雅,最主要是spring ioc和aop特性应用的得心应手。若非对源码有深入研究,不可能写出这么优秀的开源项目。另外在现有的springboot专栏中,大多数博文旨在应用,对一些中间件的整合之类,源码分析的博客数量有限。鉴于以上两方面,该系列应运而生。 该系列主要还是Spri...

程序员阿康 13万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

springboot2|springboot启动流程源码分析:tomcat启动原理

本文基于springboot2.1.6 1 当maven引入tomcat的jar依赖时 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifac...

ice-wee的专栏 1660

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Alian解读SpringBoot 2.6.0 源码(二):启动流程分析之监听器解析

一、背景 1.1、run方法整体流程 1.2、本文解读范围 二、记录应用启动的开始时间 三、初始化启动上下文 3.1、初始化启动上下文 3.2、初始化应用程序事件广播器 3.3、初始化应用上下文 四、设置无头属性 4.1、设置无头属性 五、创建并发布运行监听器 5.1、获取所有运行监听器 5.2、开始启动事件发布运行监听器 5.3、事件发布运行监听器 5.4、事件发布广播器 5.5、获取符合事件的监听器 5.6、事件匹配 5.7、监听器执行 结语

嘉禾嘉宁papa 6178

SpringBoot2 SpringBoot启动流程源码分析(一)_springboot2启动流程源码分析

前阵子看到了SpringCloud社区的一个开源项目,主要是对服务发现增强的功能。研究项目的时候发现代码简练,优雅,最主要是spring ioc和aop特性应用的得心应手。若非对源码有深入研究,不可能写出这么优秀的开源项目。另外在现有的springboot专栏中,大多数博文旨在应用,对一些中间件的整合之类,源码分析的博客数量有限。鉴于以上两方面,该系列应运而生。该系列主要还是Spring的核心源码,不过目前Springboot大行其道,所以就从Springboot开始分析。

2301_82242459的博客 473

Spring Boot 源码学习 (一) —— 启动源码解读 (上)

Spring boot 启动源码解读 本文的源码解读Spring boot版本是基于2.2.6,算是当前比较新的一个版本,当然刚观察了下官网,还有2.3.0.RC1,以及2.2.7这两个更新点的,但于本文影响不大。 public static void main(String[] args) { SpringApplication.run(ServerApplication.cl...

码客山威 273

一起来看SpringBoot2源码(1)

用了很久的spring全家桶,一直没有时间深入挖掘一下,趁着年关将近,督促自己每天拿出一小时来研究这个工具内部的原理。 本文参考了battcn唐亚峰的学习路径,在此表示感谢。 1. 我们都知道SpringBoot2的故事都是从一个函数开始的: @RestController @SpringBootApplication public class DemoApplication { pub...

sinat_25444819的博客 991

SpringBoot启动全流程源码解析(超详细版)

我们在使用SpringBoot启动项目的时候,可能只需加一个注解,然后启动main,整个项目就运行了起来,但事实真的是所见即所得吗,还是SpringBoot在背后默默做了很多?本文会通过源码解析的方式深入理解SpringBoot启动全过程 SpringBoot启动过程流程图 源码解析 大家不要抗拒源码解析,这个非常优秀的代码,我们如果能够学会对自己代码编写水平大有裨益 首先,我们先来看下SpringBoot项目的启动类 @SpringBootApplication public class Sp.

July的博客 2万+

SpringBoot 启动流程

方法来启动 Spring Boot 应用程序。该方法接受两个参数,第一个参数是启动类的类对象,第二个参数是主方法的参数。方法中做了一系列操作来完成项目启动所需的初始化Spring容器、启动内置tomcat、启动应用程序以及通知监听者等步骤。总的来说,Spring Boot的启动过程是一个复杂的流程,从启动类的Main方法中调用。启动类必须使用 @SpringBootApplication 注解标记该类。方法开始,然后在SpringApplication对象的。方法来执行项目启动的后续操作。

qq_33807380的博客 9554
上一篇: SpringBoot 源码解析1:环境搭建
下一篇: SpringBoot 源码解析3:事件监听器
hao9e
博客等级 码龄7年 189粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值