SpringBoot原理分析-1
SpringBoot原理分析
作为一个javaer,和boot打交道是很常见的吧。熟悉boot的人都会知道,启动一个springboot应用,就是用鼠标点一下启动main方法,然后等着就行了。我们来看看这个main里面。
@SpringBootApplication
public class ExampleApplication {public static void main(String[] args) {SpringApplication.run(ExampleApplication.class, args);}
}
这个类很简单吧,有三个注意点。
- ExampleApplication就是类名,为了规范起见,这个类名一般都是xxxApplication。
- 有一个注解@SpringBootApplication。
- 然后就一个main方法,里面使用了SpringApplication的静态方法run(),传进去了俩参数。
这就神奇地启动起来了,为什么呢?
分析的版本:SpringBoot 2.7.18
需要结合以前用xml文件来配置Spring容器的形式来对比Boot用注解的形式
1.注解&自动配置
目前只知道注解的作用即可,至于这些注解是怎么起作用的,见后续…
@SpringBootApplication
这一节来详细聊一聊这个注解。@SpringBootApplication
是 Spring Boot 框架中的一个核心注解,用于简化 Spring Boot 应用的配置和启动
它的作用
@SpringBootApplication
标注在应用的主类上,用于启动 Spring Boot 应用。- 它启用了 Spring Boot 的自动配置机制,根据项目的依赖自动配置 Spring 应用。
- 组件扫描:它启用了组件扫描,自动发现并注册带有
@Component
、@Service
、@Repository
、@Controller
等注解的类。 - 配置类:它标记该类为 Spring 的配置类,相当于
@Configuration
注解。
点进去看看,该注解的结构如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited // 四个元注解
@SpringBootConfiguration
@EnableAutoConfiguration //启用SpringBoot的自动配置机制。SpringBoot会根据类路径中的依赖自动配置应用。例如,如果类路径中有spring-boot-starter-web,SpringBoot会自动配置Tomcat和SpringMVC。@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 启用组件扫描,并排除一些特定的过滤器。默认是注解标注的类所在包及其子包。实际上是不是就是主启动类所在包及其子包!!!!!
public @interface SpringBootApplication {
..............
}// 发现这是一个组合注解
@SpringBootConfiguration
注解:主要作用是标记一个类为 Spring Boot 的配置类与 @Configuration
类似,但它专门用于 Spring Boot 应用。这个注解和@ComponentScan注解结合到一起,达成了如下效果。(左边是xml文件配置形式,右边是SpringBoot注解的形式),这俩注解在一起,就是扫描主启动类所在包及其子包下的被@Controller、@Service、…标注的类,将他们归到Spring容器里面去。
@EnableAutoConfiguration
@EnableAutoConfiguration
注解: 这个注解不得了啊。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 这里。
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};}
发现@Import注解。这个注解的作用是干啥的?这里给出GPT的回答:@Import
是 Spring 框架提供的一个注解,用于将一个或多个配置类(@Configuration
类)或组件类导入到当前的 Spring 应用上下文中。它可以用来显式地引入其他配置类或 Bean 定义,从而实现模块化配置和代码复用。
这里有一个非常重要的东西,那就是当前的Spring上下文,也就是主启动类所在包及其子包
,@Import(AutoConfigurationImportSelector.class)这句话的意思是将SpringBoot官方写的AutoConfigurationImportSelector类导入到当前Spring上下文中,在当前Spring上下文注册这样一个bean。
AutoConfigurationImportSelector探究
public interface ImportSelector {String[] selectImports(AnnotationMetadata importingClassMetadata);
}
// 实现了DeferredImportSelector接口,DeferredImportSelector实现了ImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {...........AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); // 1.进去return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}// 2.这个方法protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 3.进入这里List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);...........}// 4. 3调用的这个方法protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList<>(// 5. 继续往下SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}// 6. 5处调用的方法public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {...... // loadSpringFactoriesreturn loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}// 7// 最终可以在loadSpringFactories方法里面看到这样一行代码//Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);// public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";// 结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。
}
结合idea打断点调试:我们发现getCandidateConfigurations扫描到了引入的所有jar包的META-INF/spring.factories,共有156个xxxAutoConfigure类。但是这些都会用到吗,别忘了,SpringBoot有个非常强大的特点:那就是导入场景、对应的场景才会生效!!
继续往下走,请看下图:(发现只有50个了,例如上图里面的amqp,由于项目中没有用到,故在这里就没有了,经过了filter过滤)
以RabbitMq自动配置为例
@AutoConfiguration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class }) // 这两个类存在时才生效,项目里面没导入相关jar包,故RabbitAutoConfiguration不会被导入Spring容器生效,下面就来说这个注解
@EnableConfigurationProperties(RabbitProperties.class)
@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })
public class RabbitAutoConfiguration {................
}
@ConditionalOnClass
先看看其源码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class) // 这里***
public @interface ConditionalOnClass {Class<?>[] value() default {};String[] name() default {};
}
@ConditionalOnClass注解的作用是当项目中存在某个类时才会使标有该注解的类或方法生效;
先看我们的主类**【1. 此时,没有引入test.demo.test.list.Student所在的maven依赖】**
/* 下面是这俩类
public class Cat {private Integer id;private String name;
}
public class Dog {private Integer id;private String name;
}*/@SpringBootApplication
@MapperScan("com.feng.tackle.dao")
public class DateApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DateApplication.class, args);ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();Iterator<String> iterator = beanFactory.getBeanNamesIterator();while (iterator.hasNext()) {String name = iterator.next();if ( name.equals("dog01") || name.equals("cat01") ) System.out.println(name); // 看看有没有这两个名字的bean}}
}
// 最后的输出结果
/*
cat01
*/
在配置类中,我们这样做
@Configuration
public class ConditionTestConfig {@ConditionalOnClass(name = "test.demo.test.list.Student") // 类路径有这个类,就往容器中放入该bean@Beanpublic Dog dog01() {return new Dog(2, "汪汪汪");}@ConditionalOnMissingClass("test.demo.test.list.Student") // 类路径没有这个类,就往容器中放入该bean@Beanpublic Cat cat01() {return new Cat(1, "喵喵喵");}
}
main最后的输出结果是cat01。"test.demo.test.list.Student"是另一个maven项目里面的类。
【2. 项目中引入Student所在的maven】
<dependency><groupId>com.feng.test</groupId><artifactId>test-demo</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
再次启动main,输出结果dog01
通过这个例子,我们可以知道SpringBoot自动配置,导入具体starter,对应的场景才会生效。【由于没有导入MQ的starter,故此配置类不会生效】
总结
**自动配置: **
以spring-boot-starter-web为例子,引入该启动器,他的父级pom里面有spring-boot-starter,spring-boot-starter的父级pom有spring-boot-autoconfigure。
spring-boot-autoconfigure里面有Spring官方定义的所有场景。
@EnableAutoConfiguration
注解:这是自动配置的入口,通常由@SpringBootApplication
注解组合引入。spring.factories
文件:Spring Boot 通过META-INF/spring.factories
文件加载自动配置类。- 条件化配置:通过
@Conditional
系列注解(如@ConditionalOnClass
、@ConditionalOnMissingBean
等)实现按需加载配置。
自动配置的流程:
- 加载自动配置类
@SpringBootApplication
注解:该注解是一个组合注解,包含了@EnableAutoConfiguration
,用于启用自动配置。@EnableAutoConfiguration
的作用:该注解会通过SpringFactoriesLoader
加载META-INF/spring.factories
文件中定义的自动配置类。
- 条件化配置
自动配置类通常使用 @Conditional
系列注解来控制是否生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {// 自动配置逻辑
}
//如果类路径中存在 DataSource 和 EmbeddedDatabaseType,且容器中没有 ConnectionFactory Bean,则自动配置 DataSource。
- 加载配置属性
@EnableConfigurationProperties
:自动配置类通常会通过该注解加载配置属性。application.properties
或application.yml
:Spring Boot 会读取这些配置文件中的属性,并将其绑定到对应的配置类中。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {private String url;private String username;private String password;// getters and setters
}
- 注册bean
- 自动配置类通过
@Bean
方法向容器中注册 Bean。 - 这些 Bean 通常是框架的核心组件,如
DataSource
、DispatcherServlet
、SecurityFilterChain
等。
2. 启动过程
SpringApplication.run(ExampleApplication.class, args);
这一行代码做了啥?这才是重点!
从run开始看,一层一层往下面点进去
// 1.
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { // 会返回一个正在运行的Spring容器return run(new Class<?>[] { primarySource }, args); // 调用重载的run方法
}
// 2.
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); // 先调用该构造方法,然后再调用run方法,将程序参数传进去
}
// 3.
public SpringApplication(Class<?>... primarySources) {this(null, primarySources); //primarySource 是传入的主配置类(通常带有 @SpringBootApplication 注解的类),Spring Boot 会将其作为配置源。
}// 4. [构造方法] 构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {........ // 见下一节构造方法
}
先调用该构造方法,然后再调用run方法
①构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader; // null的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(); // 六、通过堆栈信息推断出主类(即 main 方法所在的类)。
}
1.推断应用类型
WebApplicationType.deduceFromClasspath()
方法会根据类路径中是否存在特定的类来推断应用类型。- 可能的类型包括:
WebApplicationType.SERVLET
:基于 Servlet 的 Web 应用(如 Spring MVC)。WebApplicationType.REACTIVE
:基于 Reactive 的 Web 应用(如 Spring WebFlux)。WebApplicationType.NONE
:非 Web 应用。
2.加载并初始化 BootstrapRegistryInitializer
实例
分析一下核心方法getSpringFactoriesInstances,下面两个都会调用这个。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 下一步List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;
}// SpringFactoriesLoader.loadFactoryNames(type, classLoader) 到这儿来了
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}//loadSpringFactories(classLoaderToUse)
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {// static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();// 从缓存map中拿到对应classLoader的map,如果该classLoader已经存在了,就不用走下面的了Map<String, List<String>> result = cache.get(classLoader);if (result != null) {return result;}result = new HashMap<>();try {/*public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。*/Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);..............return result;
}
可以看到这里,在第一章《注解&自动配置》也出现了这个,如今在SpringApplication的构造方法,底层也调用到了这里。二者有什么区别或者联系呢?
SpringFactoriesLoader.loadFactoryNames
是Spring Boot 提供的工具方法,用于从 META-INF/spring.factories
文件中加载指定类型的配置类。
两者都依赖于 META-INF/spring.factories
文件,该文件是 Spring Boot 自动配置和扩展机制的核心配置文件。两者都通过类路径扫描,加载所有 META-INF/spring.factories
文件,并解析出指定类型的配置类。
(1)调用位置
AutoConfigurationImportSelector
:- 位于
org.springframework.boot.autoconfigure
包中。 - 是 Spring Boot 自动配置的核心组件之一,负责加载自动配置类。
- 在 Spring 容器的配置类解析阶段被调用(具体是在
@EnableAutoConfiguration
注解的处理过程中)。
- 位于
SpringApplication
:- 位于
org.springframework.boot
包中。 - 是 Spring Boot 应用的启动类,负责初始化应用上下文、加载配置等。
- 在应用启动时被调用。
- 位于
(2)加载的配置类型
AutoConfigurationImportSelector
:- 主要加载
META-INF/spring.factories
文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration
键下的自动配置类。 - 这些配置类用于实现 Spring Boot 的自动配置功能(如
DataSourceAutoConfiguration
、WebMvcAutoConfiguration
等)。
- 主要加载
SpringApplication
:- 加载多种类型的配置类,包括:
ApplicationContextInitializer
ApplicationListener
BootstrapRegistryInitializer
- 这些配置类用于初始化应用上下文、监听应用事件等。
- 加载多种类型的配置类,包括:
(3)调用时机
AutoConfigurationImportSelector
:- 在 Spring 容器解析配置类时调用(具体是在
ConfigurationClassPostProcessor
处理@Configuration
类时)。 - 属于 Spring 容器初始化的早期阶段。
- 在 Spring 容器解析配置类时调用(具体是在
SpringApplication
:- 在应用启动时调用(具体是在
SpringApplication
的构造方法或run
方法中)。 - 属于应用启动的早期阶段。
- 在应用启动时调用(具体是在
(4)返回值的使用
AutoConfigurationImportSelector
:- 返回的自动配置类会被 Spring 容器加载并处理,最终生成相应的 Bean 定义。
- 这些配置类通常包含
@Configuration
注解和@Conditional
注解,用于按需加载 Bean。
SpringApplication
:- 返回的配置类会被直接实例化并注册到应用中。
- 例如,
ApplicationContextInitializer
会被调用以初始化应用上下文,ApplicationListener
会被注册以监听应用事件。
3.加载并设置 ApplicationContextInitializer
实例
同2
4.加载并设置 ApplicationListener
实例
同2
总结
BootstrapRegistryInitializer
:用于应用启动的最早阶段,初始化引导阶段的组件。ApplicationContextInitializer
:用于在ApplicationContext
创建之后、刷新之前,对上下文进行自定义初始化。ApplicationListener
:用于监听应用生命周期中的事件,并在特定阶段执行逻辑。
这三者共同扩展了 Spring Boot 应用的启动过程,提供了灵活的扩展点,可以满足不同场景下的需求。
5.三者的实现
分别编写实现类
public class MyBootstrapInit implements BootstrapRegistryInitializer {@Overridepublic void initialize(BootstrapRegistry registry) {System.out.println("【MyBootstrapInit】--------------方法执行了");}
}public class MyApplicationContextInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("【MyApplicationContextInit】------------" + applicationContext.getApplicationName());}
}public class MyContextListener implements ApplicationListener<ApplicationStartedEvent> { // 该监听器对此事件感兴趣@Overridepublic void onApplicationEvent(ApplicationStartedEvent event) {System.out.println("【MyContextListener】--监听器--" + event.getSource());}
}
然后在resource目录下面创建META-INF,在其中的spring.factories中
org.springframework.boot.BootstrapRegistryInitializer=com.feng.tackle.config.source.MyBootstrapInit
org.springframework.context.ApplicationContextInitializer=com.feng.tackle.config.source.MyApplicationContextInit
org.springframework.context.ApplicationListener=com.feng.tackle.config.source.MyContextListener
启动应用:
疑问? 我可以在这三者的实现类上面加@Configuration注解,不要spring.factories,可以实现类似效果吗?
答案是,只有ApplicationListener可以。为什么?请看下面的run方法里面
②run
public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间,用于后续计算启动耗时。long startTime = System.nanoTime(); //创建一个 BootstrapContext,用于在应用启动的早期阶段提供一些基础设施支持(如环境配置、属性源等)================DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 设置系统属性 java.awt.headless,确保应用在没有图形界面环境(如服务器)中也能正常运行configureHeadlessProperty();/*获取所有 SpringApplicationRunListener 实例,用于监听应用启动的各个阶段。调用 listeners.starting(),通知监听器应用正在启动。*/SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 加载和配置应用的环境(Environment),包括配置文件(如 application.properties 或 application.yml)、命令行参数等。ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印 Spring Boot 的启动 Banner(默认或自定义)。Banner printedBanner = printBanner(environment);// 根据应用类型(Servlet、Reactive 等)创建相应的 ApplicationContext。context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备应用上下文prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 调用 AbstractApplicationContext.refresh() 方法,完成 Bean 的实例化、依赖注入和初始化。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);// 执行所有 ApplicationRunner 和 CommandLineRunner 的实现类,用于在应用启动后执行自定义逻辑。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;
}
这个run这里分析得不够深入。受篇幅影响,在后续文章中再来分析。
end. 参考
- 尚硅谷雷丰阳老师的课
相关文章:
SpringBoot原理分析-1
SpringBoot原理分析 作为一个javaer,和boot打交道是很常见的吧。熟悉boot的人都会知道,启动一个springboot应用,就是用鼠标点一下启动main方法,然后等着就行了。我们来看看这个main里面。 SpringBootApplication public class E…...
我用Ai学Android Jetpack Compose之Button
答案来自 通义千问,代码同样需要到Android Studio里实践,才能学会。 我要学Button,麻烦介绍一下 当然可以!Button 是 Jetpack Compose 中用于创建可点击按钮的 Composable 函数。它提供了丰富的配置选项来定制按钮的外观和行为。…...
《量子比特:解锁人工智能并行计算加速的密钥》
在科技飞速发展的今天,量子计算与人工智能的融合正成为一股强大的力量,为诸多领域带来变革性的突破。量子比特作为量子计算的核心要素,其独特的叠加和纠缠特性为人工智能算法实现并行计算加速提供了前所未有的机遇。 量子比特的叠加特性&…...
【SpringBoot】当 @PathVariable 遇到 /,如何处理
1. 问题复现 在解析一个 URL 时,我们经常会使用 PathVariable 这个注解。例如我们会经常见到如下风格的代码: RestController Slf4j public class HelloWorldController {RequestMapping(path "/hi1/{name}", method RequestMethod.GET)publ…...
用QT实现 端口扫描工具1
安装在线QT,尽量是完整地自己进行安装,不然会少包 参考【保姆级图文教程】QT下载、安装、入门、配置VS Qt环境-CSDN博客 临时存储空间不够。 Windows系统通常会使用C盘来存储临时文件。 修改临时文件存储位置 打开系统属性: 右键点击“此电…...
基于单片机的肺功能MVV简单测算
肺功能MVV一般是指肺部每分钟的最大通气量。 MVV本身是最大值的英文缩写,在临床上,肺功能MVV表示肺部每分钟最大通气量,用以衡量气道的通畅度,以及肺部和胸廓的弹性、呼吸肌的力量。 肺部每分钟的最大通气量的参考值男性与女性之…...
入手STM32单片机学习指南
目录 引言 一、基础概念 1.1 STM32单片机简介 1.2 ARM Cortex-M系列处理器 1.3 微控制器的基本组成 二、开发环境搭建 2.1 选择开发板 2.2 安装开发软件 2.3 配置开发环境 三、编程入门 3.1 GPIO编程 3.2 UART编程 3.3 ADC编程 引言 STM32单片机是基于ARM Cortex…...
无法定位软件包cuda
无法定位软件包cuda 如果你在使用 sudo apt install cuda 命令安装 CUDA 时遇到“无法定位软件包cuda”的问题,这可能是由于你的系统没有正确配置 CUDA 的安装源。以下是一些可能的解决方案: 更新 Ubuntu 软件源并升级到最新版本的软件包。你可以选择使…...
GWAS数据和软件下载
这部分主要是数据获取,以及软件配置方法。 一、配套数据和代码 数据和代码目前在不断的更新,最新的教程可以私信,我通过后手动发送最新版的pdf和数据代码。发送的压缩包,有电子版的pdf和数据下载链接,里面是最新的百度网盘的地址,下载到本地即可。然后根据pdf教程,结合配套的…...
SpringBoot3-深入理解自动配置类的原理(尚硅谷SpringBoot3-雷神)
文章目录 目录了解自动配置 一、导入对应场景的Mean依赖:1、引入依赖**找到自动配置类的所有配置都存放在哪里** 二、编写主程序:SpringBootApplication观察源码时所需要知道的几个核心注解:1、观察SpringBootApplication源码都做了什么 三、…...
MOE怎样划分不同专家
MOE怎样划分不同专家 目录 MOE怎样划分不同专家MOE划分不同专家的方法LLM模型拆分的方法**子模块拆分法**:**多头拆分法**:**层间拆分法****基于功能的拆分法**Python代码实现MOE划分不同专家以及LLM模型拆分的方法及举例如下: MOE划分不同专家的方法 ffn前馈神经网络 独立…...
NLP CH3复习
CH3 3.1 几种损失函数 3.2 激活函数性质 3.3 哪几种激活函数会发生梯度消失 3.4 为什么会梯度消失 3.5 如何解决梯度消失和过拟合 3.6 梯度下降的区别 3.6.1 梯度下降(GD) 全批量:在每次迭代中使用全部数据来计算损失函数的梯度。计算成本…...
Pyecharts SVG 标记使用笔记
Pyecharts SVG 标记使用笔记 在数据可视化中,图表的标记点常常用于突出显示重要数据点。Pyecharts 提供了丰富的标记点配置选项,其中使用 SVG 路径来自定义标记点的样式是一个非常强大的功能。本文将详细介绍如何在 Pyecharts 中使用 SVG 路径来定制标记…...
C++ 文件操作
文件操作 // 文件操作 // 程序运行时产生的数据都属于临时数据,程序结束后临时数据会被操作系统释放 // 通过文件操作可以将数据持久化 // c 中文件操作需要包含头文件 <fstream>// 文件类型分为两种: // 文本文件: 文件以文本的ASCII…...
享元模式详解
享元模式详解 一、定义 享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来尽量减少内存的使用。它通过将重复使用的对象分离成共享和非共享部分,达到复用的目的,从而有效节省内存。具体来说&#x…...
数据库中的并发控制
并发操作带来的数据不一致性 1、并发控制:为了保证事务的隔离性和一致性,数据库管理系统需要对并发操作进行正确调度 并发控制的主要技术有:封锁、时间戳、乐观控制法、多版本并发控制等 并发操作带来的数据不一致性: ① 丟失修改:两个事务 T1 和 T2 读入同一数据…...
【软考网工笔记】计算机基础理论与安全——计算机硬件知识
计算机分级存储体系 计算机分级存储体系目前最常用的是三级存储体系。 CPU——CaChe(高速缓存)——主存——辅存 其中 Cache 是用于解决存取速度不够快,辅存是用于解决存储容量不够大,二者结合可在容量和速度实现提升的情况下尽可…...
SpringBoot 多种生产打包方式详解
Springboot 多种生产打包方式简介 生产上发布 Spring Boot 项目时,流程颇为繁琐且低效。但凡代码有一丁点改动,就得把整个项目重新打包部署,耗时费力不说,生成的 JAR 包还特别臃肿,体积庞大。每次更新项目,…...
WebSocket 安全实践:从认证到加密
在前三篇文章中,我们深入探讨了 WebSocket 的基础原理、服务端开发和客户端实现。今天,让我们把重点放在安全性上,看看如何构建一个安全可靠的 WebSocket 应用。我曾在一个金融项目中,通过实施多层安全机制,成功防御了多次恶意攻击尝试。 安全挑战 WebSocket 应用面临的主要安…...
实现单例模式的五种方式
如何实现一个单例 1、构造器需要私有化 2、提供一个私有的静态变量 3、暴露一个公共的获取单例对象的接口 需要考虑的两个问题 1、是否支持懒加载 2、是否线程安全 1、饿汉式 public class EagerSingleton {private static final EagerSingleton INSTANCE new EagerSi…...
【Go学习】-01-6-数据库泛型新特性
【Go学习】-01-6-数据库泛型新特性 1 数据库操作1.1 操作mysql1.1.1 Insert1.1.2 Select1.1.3 Update1.1.4 Delete1.1.5 sql事务 1.2 go操作Redis 2 泛型2.1 非泛型函数2.2 泛型函数2.3 泛型类型2.3.1 泛型结构体2.3.2 泛型接口 2.4 泛型约束2.5 泛型切片和映射2.5.1 泛型切片2…...
算法学习(22)—— BFS解决最短路问题
关于最短路问题 最短路问题是“图论”里非常重要的一类问题,涉及的内容非常多,在这个专题里,我们主要讲“边权为1的最短路问题”,因为这个比较基础比较简单而关于啥是“边权为1的最短路问题”,我们通过下面的例子来讲…...
【双层模型】考虑供需双侧的综合能源双层优化模型
目录 主要内容 内容研究 1.模型简介 2 程序释义 部分代码 运行结果 下载链接 主要内容 该程序实现一个综合能源系统的优化调度双层模型,上下层分别采用差分进化算法和规划算法进行求解。模型考虑了多种能源设备,包括燃气轮机、燃气锅炉、风电…...
【读书笔记/源码】How Tomcat Works 笔记- c11~c13
chapter11: standardwrapperchapter12: 无程序 第十章 安全性 servlet容器是通过一个名为验证器的阀来支持安全限制的。当servlet容器启动时,验证器阀会被添加到Context容器的管道中。 验证器阀会调用Context容器的领域对象的authenticate()方法,传入…...
Electron快速入门——跨平台桌面端应用开发框架
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
Vision Transformer模型详解(附pytorch实现)
写在前面 最近,我在学习Transformer模型在图像领域的应用。图像处理任务一直以来都是深度学习领域的重要研究方向,而传统的卷积神经网络已在许多任务中取得了显著的成绩。然而,近年来,Transformer模型由于其在自然语言处理中的成…...
中国区域创新创业指数IRIEC数据(省级、地市级)1990-2020年-社科数据
中国区域创新创业指数IRIEC数据(省级、地市级)1990-2020年-社科数据https://download.csdn.net/download/paofuluolijiang/90028728 https://download.csdn.net/download/paofuluolijiang/90028728 中国区域创新创业指数(IRIEC)…...
Elasticsearch:减少 Elastic 容器镜像中的 CVE(常见的漏洞和暴露)
作者:来自 Elastic Maxime Greau 在这篇博文中,我们将讨论如何通过在 Elastic 产品中切换到最小基础镜像并优化可扩展漏洞管理程序的工作流程来显著减少 Elastic 容器镜像中的常见漏洞和暴露 (Common Vulnerabilities and Exposures - CVEs)。 基于 Chai…...
webpack02
webpack中常用loader postcss-loader 在css-loader之前,对css进行一些操作,,,比如统一加前缀,,或者是重置样式,,, 这个postcss-loader会自己去找 postcss工具࿰…...
腾讯云更改用户为root
最近买了台99元一年的2核的云服务器,方便学习一些java开发中间件,以及部署一些项目。 1.设置root用户密码 sudo passwd root 2.修改配置文件 ll /etc | grep ssh cd /etc/ssh/ ls vim sshd_config 输入/PasswordAuthentication 寻找 输入:set nu 再按下…...
Excel导入导出-若依版本
最终效果 1、导出 1、在实体类上加注解 Excel(name “客户类型名称”) ToString AllArgsConstructor NoArgsConstructor public class UserType extends BaseEntity2 implements Serializable {Excel(name "客户类型ID", cellType Excel.ColumnType.NUMERIC…...
【Qt】快速添加对应类所需的头文件包含
快速添加对应类所需的头文件包含 一,简介二,操作步骤 一,简介 本文介绍一下,如何快速添加对应类所需要包含的头文件,可以提高开发效率,供参考。 二,操作步骤 以QTime类为例: 选中…...
基于服务器部署的综合视频安防系统的智慧快消开源了。
智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。国产化人工智能“…...
浅谈棋牌游戏开发流程七:反外挂与安全体系——守护游戏公平与玩家体验
一、前言:为什么反外挂与安全这么重要? 对于任何一款线上棋牌游戏而言,公平性和玩家安全都是最重要的核心要素之一。如果游戏环境充斥着各式各样的外挂、作弊方式,不仅会毁坏玩家体验,更会导致游戏生态崩塌、口碑下滑…...
Laravel操作ElasticSearch
在Laravel项目中操作ElasticSearch可以通过以下步骤来实现,通常会借助相应的ElasticSearch客户端扩展包。 ### 安装ElasticSearch客户端包 在Laravel项目中,常用的是 elasticsearch/elasticsearch 这个PHP客户端库来与ElasticSearch进行交互,…...
缓存-文章目录
关于缓存系列文章: 缓存学习总结1(缓存分类) 缓存学习总结2(服务器本地缓存) 缓存学习总结3(服务器内存缓存)推荐使用 缓存学习总结4(分布式缓存) 关于redis系列文章…...
安装教程:慧集通集成平台(DataLinkX)智能体客户端安装操作(Linux/windows/mac)
1.下载客户端 使用提供的账号登录集成平台后台(https://www.datalinkx.cn/),点击左侧菜单栏【智能体】→【智能体】进入到智能体列表界面,在该界面我们找到功能栏中的下载按钮点击则会弹出下载界面,在该界面我们可以选择不同的系统操作系统来下载对应版…...
解决vmware虚拟机和宿主机之间不能复制粘贴
在虚拟机内执行一下命令 /usr/bin/vmware-user 更多解决方案 https://www.cnblogs.com/wutou/p/17629408.html...
由源程序到运行
由源程序到运行 第一步:编写源程序 assume cs:codesg codesg segmentmov ax,0123Hmov bx,0456Hadd ax,bxadd ax,axmov ax,4c00hint 21h codesg ends end第二步:进行编译 进入到编译目录 编译 .asm文件生成目标文件(.obj) m…...
Java-JDBC的使用
目录 一、JDBC(java数据库连接):java database connector 二、使用JDBC的步骤 三、加条件查询 四、预处理(防止SQL注入) 五、Statement和PreparedStatement的优略 六、将数据中的数据查询出来后需要保存在一个集合中,方便前端…...
如何优化亚马逊广告以提高ROI?
在竞争激烈的亚马逊市场中,优化广告以提高投资回报率(ROI)是卖家的关键任务。以下是一些实用的策略: 一、精准的关键词研究与选择 深入了解产品特性和目标受众 详细分析产品的功能、用途、优势和适用人群。例如,如果你…...
身是菩提树,心如明镜台;时时勤拂拭,莫使惹尘埃。
神秀: 身是菩提树,心如明镜台;时时勤拂拭,莫使惹尘埃。 第一个毛病1: 在神秀看来,修行就是要保持我们本来干净的心, 跟外部世界的灰尘之间的隔绝状态,始终保持这种隔绝, 尘世是什么? 尘就是烦恼,人世间无处不是烦恼&a…...
如何修复富士相机卡错误并恢复卡数据
富士相机以其卓越的图像质量而闻名,但不幸的是,其 SD 卡错误可能会意外发生,导致数据丢失和摄影会话中断。 在本指南中,我们将引导您了解常见的富士相机 SD 卡错误、如何修复这些错误,以及如何有效地从损坏的卡中恢复…...
呼叫中心中间件实现IVR进入排队,判断排队超时播放提示音
文章目录 [TOC](文章目录) 前言需求排队结束原因 联系我们实现步骤1. 调用http接口返回动作2. 启用拨号方案 前言 需求 呼叫中心需要实现调用IVR接口进入排队,如果是因为等待超时导致退出排队的,那就播放一段提示音再挂断通话;其他的情况就…...
数据分析思维(八):分析方法——RFM分析方法
数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python,更重要的是数据分析思维。没有数据分析思维和业务知识,就算拿到一堆数据,也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》,本文内容就是提取…...
SpringBoot3动态切换数据源
背景 随着公司业务战略的发展,相关的软件服务也逐步的向多元化转变,之前是单纯的拿项目,赚人工钱,现在开始向产品化\服务化转变。最近雷袭又接到一项新的挑战:了解SAAS模型,考虑怎么将公司的产品转换成多租…...
Java虚拟机面试题:内存管理(上)
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
WPF通过反射机制动态加载控件
Activator.CreateInstance 是 .NET 提供的一个静态方法,它属于 System 命名空间。此方法通过反射机制根据提供的类型信息。 写一个小demo演示一下 要求:在用户反馈界面点击建议或者评分按钮 弹出相应界面 编写MainWindow.xmal 主窗体 <Window x:C…...
前端学习-操作元素属性(二十三)
前言 假期快乐,大家加油 操作元素属性 操作元素常用属性 还可以通过 JS 设置/修改标签元素属性,比如通过 src更换 图片最常见的属性 比如:href、title、src等语法:对象.属性 值 const pic document.querySelector(img);pic.src ./images/b0.jpgp…...
Javascript 编写的一个红、黄、绿灯交替变亮
为了创建一个简单但功能完整的交通灯程序,我们将使用 HTML、CSS 和 JavaScript 来实现红、黄、绿三种颜色按照规定的顺序循环显示。这个例子将确保灯光按照红 -> 绿 -> 黄的顺序循环,并且可以调整每个灯光的持续时间以模拟真实的交通灯行为。 效果…...