springboot 启动原理

news2025/2/4 14:48:45

目标:

  1. @SpringBootApplication注解认识
  2. 了解SpringBoot的启动流程
    • 了解SpringFactoriesLoader对META-INF/spring.factories的反射加载
    • 认识AutoConfigurationImportSelector这个ImportSelector
  3. starter的认识和使用

目录

  • SpringBoot 启动原理
    • @SpringBootApplication 注解分析
      • @EnableAutoConfiguration注解
      • AutoConfigurationImportSelector类
      • eg:AutoConfigurationImportSelector扫描出mybatis-spring-starter的spring.factories配置
    • new SpringApplication类
      • 附:SpringFactoriesLoader
      • 附:spring-boot的spring.factories内容
    • SpringApplication类的run方法流程
      • prepareEnvironment
      • printBanner
      • createApplicationContext
      • prepareContext
      • refreshContext
        • ImportSelector 的 selectImports 方法
    • 再次说明starter
      • SpringBoot starter机制
      • 自定义一个starter并引用

SpringBoot 启动原理

springboot项目启动主类如下

@SpringBootApplication
@ComponentScan("com.example")
@EnableScheduling
public class DemoApiApplication {

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

主要就是@SpringBootApplication这个注解

@SpringBootApplication 注解分析

  • @SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
  • @SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

可以看到全注解类的@Configuration注解

  • @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

@EnableAutoConfiguration注解

EnableAutoConfiguration是一个组合注解,用@ImportAutoConfigurationImportSelector导入容器中,SpringBoot启动的时候会加载所有的selector并执行selectImports方法,这个方法会加载META-INF/spring.factories中配置的EnableAutoConfiguration,从而实现加载自动配置

mybatis-spring-boot-starterspring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

在这里插入图片描述

AutoConfigurationImportSelector类

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {

在这里插入图片描述

AutoConfigurationImportSelector实现了ImportSelector(选择器)和BeanClassLoaderAware(bean类加载器中间件)

关于ImportSelector在https://blog.csdn.net/qq_26437925/article/details/144865082 这篇文章中有分析到,即在使用@Import注解来注册bean的时候(Import注解的值可以是ImportSelector或者DeferredImportSelector的实现类)spring容器会实例化这个实现类,并执行其selectImports方法;

具体是在 spring refresh 12 个方法中的invokeBeanFactoryPostProcessors(beanFactory);会执行ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法中

eg:AutoConfigurationImportSelector扫描出mybatis-spring-starter的spring.factories配置

在这里插入图片描述
debug Springboot启动过程
在这里插入图片描述

new SpringApplication类

/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param resourceLoader the resource loader to use
	 * @param primarySources the primary bean sources
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@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();
		// 通过SpringFactoriesLoader,获取到所有META-INF/spring.factories中的ApplicationContextInitializer,并实例化
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		// 通过SpringFactoriesLoader,获取到所有META-INF/spring.factories中的ApplicationListener,并实例化
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 获取执行当前main方法的类,也就是启动类
		this.mainApplicationClass = deduceMainApplicationClass();
	}
  • 判断应用类型为 WebApplicationType.SERVLET

  • 利用SpringFactoriesLoader加载所有META-INF/spring.factories中的ApplicationContextInitializer
  • SpringFactoriesLoader加载所有META-INF/spring.factories中的ApplicationListener

附:SpringFactoriesLoader

其原理AI回答如下:
在这里插入图片描述

在这里插入图片描述

附:spring-boot的spring.factories内容

在这里插入图片描述

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

SpringApplication类的run方法流程

使用的spring-boot-starter版本如下

<parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.4.RELEASE</version>
 </parent>
  • org.springframework.boot.SpringApplication#run(java.lang.String…)
/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	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. 首先遍历执行所有通过SpringFactoriesLoader,在当前classpath下的META-INF/spring.factories中查找所有可用的SpringApplicationRunListeners并实例化。调用它们的starting()方法,通知这些监听器SpringBoot应用启动。

  2. 创建并配置当前SpringBoot应用将要使用的Environment,包括当前有效的PropertySource以及Profile。

  3. 遍历调用所有的SpringApplicationRunListeners的environmentPrepared()的方法,通知这些监听器SpringBoot应用的Environment已经完成初始化。

  4. 打印SpringBoot应用的banner,SpringApplication的showBanner属性为true时,如果classpath下存在banner.txt文件,则打印其内容,否则打印默认banner。

  5. 根据启动时设置的applicationContextClass和在initialize方法设置的webEnvironment,创建对应的applicationContext。

  6. 创建异常解析器,用在启动中发生异常的时候进行异常处理(包括记录日志、释放资源等)。

  7. 设置SpringBoot的Environment,注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader,通过SpringFactoriesLoader加载ApplicationContextInitializer初始化器,调用initialize方法,对创建的ApplicationContext进一步初始化。

  8. 调用所有的SpringApplicationRunListeners的contextPrepared方法,通知这些Listener当前ApplicationContext已经创建完毕。

  9. 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

  10. 调用所有的SpringApplicationRunListener的contextLoaded方法,加载准备完毕的ApplicationContext。

  11. 调用refreshContext(即spring容器refresh方法),并注册一个关闭Spring容器的钩子ShutdownHook,当程序在停止的时候释放资源(包括:销毁Bean,关闭SpringBean的创建工厂等)
    注: 钩子可以在以下几种场景中被调用:
    1)程序正常退出
    2)使用System.exit()
    3)终端使用Ctrl+C触发的中断
    4)系统关闭
    5)使用Kill pid命令杀死进程

获取当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法
遍历所有的SpringApplicationRunListener的finished()方法,完成SpringBoot的启动。

prepareEnvironment

环境准备的时候会new ApplicationEnvironmentPreparedEvent()并广播这个事件

而ConfigFileApplicationListener‌是Spring Boot中的一个监听器,主要负责配置文件的加载和处理。它通过监听特定的应用事件,来加载和解析配置文件,并将解析后的配置信息添加到Spring的环境中。会监听到

如下:
在这里插入图片描述
加载application.properties文件,具体使用的是spring-boot的spring.factories中配置的org.springframework.boot.env.PropertiesPropertySourceLoader

org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

在这里插入图片描述

PropertiesPropertySourceLoader怎么实例化出来的?

  1. 事件监听触发后,使用EnvironmentPostProcessor后处理加载配置,后处理通过SpringFactoriesLoader加载获得到
    在这里插入图片描述
  2. 然后添加配置new Loader()
/**
 * Add config file property sources to the specified environment.
 * @param environment the environment to add source to
 * @param resourceLoader the resource loader
 * @see #addPostProcessors(ConfigurableApplicationContext)
 */
protected void addPropertySources(ConfigurableEnvironment environment,
		ResourceLoader resourceLoader) {
	RandomValuePropertySource.addToEnvironment(environment);
	new Loader(environment, resourceLoader).load();
}

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. PropertySourcesPlaceholdersResolver通过SpringFactoriesLoader load出来
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(
					PropertySourceLoader.class, getClass().getClassLoader());

printBanner

在这里插入图片描述

createApplicationContext

根据webApplicationType创建ConfigurableApplicationContext,具体为:
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

prepareContext

  • profile信息设置并打印,否则使用默认的default
    在这里插入图片描述
  • 加载启动类

在这里插入图片描述

refreshContext

private void refreshContext(ConfigurableApplicationContext context) {
	refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}

如下图走到spring容器的refresh方法:
在这里插入图片描述

ImportSelector 的 selectImports 方法

在这里插入图片描述

其中List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);一句如下

/**
 * Return the auto-configuration class names that should be considered. By default
 * this method will load candidates using {@link SpringFactoriesLoader} with
 * {@link #getSpringFactoriesLoaderFactoryClass()}.
 * @param metadata the source metadata
 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
 * attributes}
 * @return a list of candidate configurations
 */
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations,
            "No auto configuration classes found in META-INF/spring.factories. If you "
                    + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

使用SpringFactoryLoader,读取META-INF/spring.factories文件里所配置的EnableAutoConfiguration。经过exclude和filter等操作,最终确定要装配的类

Spring的SpringFactoriesLoader工厂的加载机制类似java提供的SPI机制一样,是Spring提供的一种加载方式。只需要在classpath路径下新建一个文件META-INF/spring.factories,并在里面按照properties格式填写好接口和实现类即可通过SpringFactoriesLoader来实例化相应的Bean。其中key可以是接口、注解、或者抽象类的全名。value为相应的实现类,当存在多个实现类时,用","进行分割。

在这里插入图片描述

loadFactoryNames方法如下:

/**
 * Load the fully qualified class names of factory implementations of the
 * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
 * class loader.
 * @param factoryClass the interface or abstract class representing the factory
 * @param classLoader the ClassLoader to use for loading resources; can be
 * {@code null} to use the default
 * @see #loadFactories
 * @throws IllegalArgumentException if an error occurs while loading factory names
 */
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    try {
        Enumeration<URL> urls = (classLoader != null ?
                classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        result = new LinkedMultiValueMap<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                List<String> factoryClassNames = Arrays.asList(
                        StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
                result.addAll((String) entry.getKey(), factoryClassNames);
            }
        }
        cache.put(classLoader, result);
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

在这里插入图片描述

在这里插入图片描述

后续就能完成bean的自动注入了

再次说明starter

SpringBoot将所有的常见开发功能,分成了一个个场景启动器(starter),这样我们需要开发什么功能,就导入什么场景启动器依赖即可

在这里插入图片描述

SpringBoot starter机制

SpringBoot中的starter能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并允许我们调整这些配置,即遵循"约定大于配置"的理念。

自定义一个starter并引用

在这里插入图片描述

  • 其/META-INF/spring.factories的内容
#-------starter自动装配---------
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.demo.starter.config.DemoConfig
  • DemoConfig类如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.demo.starter.config;

import com.demo.starter.properties.DemoProperties;
import com.demo.starter.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties({DemoProperties.class})
@ConditionalOnProperty(
    prefix = "demo",
    name = {"isopen"},
    havingValue = "true"
)
public class DemoConfig {
    @Autowired
    private DemoProperties demoProperties;

    public DemoConfig() {
    }

    @Bean(
        name = {"demo"}
    )
    public DemoService demoService() {
        return new DemoService(this.demoProperties.getSayWhat(), this.demoProperties.getToWho());
    }
}
  • 引用并测试
	// 引入自定义的starter
	compile files('src/libs/demo-spring-boot-starter-0.0.1-RELEASE.jar')
  • 使用&测试
@RestController
public class DemoControl {

    @Resource(name = "demo")
    private DemoService demoService;

    @GetMapping("/say")
    public String sayWhat() {
        return demoService.say();
    }

}

在这里插入图片描述

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

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

相关文章

llama.cpp GGUF 模型格式

llama.cpp GGUF 模型格式 1. Specification1.1. GGUF Naming Convention (命名规则)1.1.1. Validating Above Naming Convention 1.2. File Structure 2. Standardized key-value pairs2.1. General2.1.1. Required2.1.2. General metadata2.1.3. Source metadata 2.2. LLM2.2.…

使用Pytorch训练一个图像分类器

一、准备数据集 一般来说&#xff0c;当你不得不与图像、文本或者视频资料打交道时&#xff0c;会选择使用python的标准库将原始数据加载转化成numpy数组&#xff0c;甚至可以继续转换成torch.*Tensor。 对图片而言&#xff0c;可以使用Pillow库和OpenCV库对视频而言&#xf…

S4 HANA明确税金汇差科目(OBYY)

本文主要介绍在S4 HANA OP中明确税金汇差科目(OBYY)相关设置。具体请参照如下内容&#xff1a; 1. 明确税金汇差科目(OBYY) 以上配置点定义了在外币挂账时&#xff0c;当凭证抬头汇率和税金行项目汇率不一致时&#xff0c;造成的差异金额进入哪个科目。此类情况只发生在FB60/F…

深入理解linux中的文件(上)

1.前置知识&#xff1a; &#xff08;1&#xff09;文章 内容 属性 &#xff08;2&#xff09;访问文件之前&#xff0c;都必须打开它&#xff08;打开文件&#xff0c;等价于把文件加载到内存中&#xff09; 如果不打开文件&#xff0c;文件就在磁盘中 &#xff08;3&am…

Airflow:深入理解Apache Airflow Task

Apache Airflow是一个开源工作流管理平台&#xff0c;支持以编程方式编写、调度和监控工作流。由于其灵活性、可扩展性和强大的社区支持&#xff0c;它已迅速成为编排复杂数据管道的首选工具。在这篇博文中&#xff0c;我们将深入研究Apache Airflow 中的任务概念&#xff0c;探…

93,【1】buuctf web [网鼎杯 2020 朱雀组]phpweb

进入靶场 页面一直在刷新 在 PHP 中&#xff0c;date() 函数是一个非常常用的处理日期和时间的函数&#xff0c;所以应该用到了 再看看警告的那句话 Warning: date(): It is not safe to rely on the systems timezone settings. You are *required* to use the date.timez…

ChatGPT怎么回事?

纯属发现&#xff0c;调侃一下~ 这段时间deepseek不是特别火吗&#xff0c;尤其是它的推理功能&#xff0c;突发奇想&#xff0c;想用deepseek回答一些问题&#xff0c;回答一个问题之后就回复服务器繁忙&#xff08;估计还在被攻击吧~_~&#xff09; 然后就转向了GPT&#xf…

本地部署DeepSeek教程(Mac版本)

第一步、下载 Ollama 官网地址&#xff1a;Ollama 点击 Download 下载 我这里是 macOS 环境 以 macOS 环境为主 下载完成后是一个压缩包&#xff0c;双击解压之后移到应用程序&#xff1a; 打开后会提示你到命令行中运行一下命令&#xff0c;附上截图&#xff1a; 若遇…

2月3日星期一今日早报简报微语报早读

2月3日星期一&#xff0c;农历正月初六&#xff0c;早报#微语早读。 1、多个景区发布公告&#xff1a;售票数量已达上限&#xff0c;请游客合理安排行程&#xff1b; 2、2025春节档总票房破70亿&#xff0c;《哪吒之魔童闹海》破31亿&#xff1b; 3、美宣布对中国商品加征10…

WPF进阶 | WPF 动画特效揭秘:实现炫酷的界面交互效果

WPF进阶 | WPF 动画特效揭秘&#xff1a;实现炫酷的界面交互效果 前言一、WPF 动画基础概念1.1 什么是 WPF 动画1.2 动画的基本类型1.3 动画的核心元素 二、线性动画详解2.1 DoubleAnimation 的使用2.2 ColorAnimation 实现颜色渐变 三、关键帧动画深入3.1 DoubleAnimationUsin…

DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”

当算力博弈升级为网络战争&#xff1a;拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下&#xff0c;网络已然成为人类社会运转的关键基础设施&#xff0c;深刻融入经济、生活、政务等各个领域。从金融交易的实时清算&#xf…

本地部署DeepSeek-R1模型(新手保姆教程)

背景 最近deepseek太火了&#xff0c;无数的媒体都在报道&#xff0c;很多人争相着想本地部署试验一下。本文就简单教学一下&#xff0c;怎么本地部署。 首先大家要知道&#xff0c;使用deepseek有三种方式&#xff1a; 1.网页端或者是手机app直接使用 2.使用代码调用API …

DRM系列七:Drm之CREATE_DUMB

本系列文章基于linux 5.15 DRM驱动的显存由GEM&#xff08;Graphics execution management&#xff09;管理。 一、创建流程 创建buf时&#xff0c;user层提供需要buf的width,height以及bpp(bite per pixel)&#xff0c;然后调用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &…

二叉树——429,515,116

今天继续做关于二叉树层序遍历的相关题目&#xff0c;一共有三道题&#xff0c;思路都借鉴于最基础的二叉树的层序遍历。 LeetCode429.N叉树的层序遍历 这道题不再是二叉树了&#xff0c;变成了N叉树&#xff0c;也就是该树每一个节点的子节点数量不确定&#xff0c;可能为2&a…

使用mybatisPlus插件生成代码步骤及注意事项

使用mybatisPlus插件可以很方便的生成与数据库对应的PO对象&#xff0c;以及对应的controller、service、ImplService、mapper代码&#xff0c;生成这种代码的方式有很多&#xff0c;包括mybatis-plus提供的代码生成器&#xff0c;以及idea提供的代码生成器&#xff0c;无论哪一…

SmartPipe完成新一轮核心算法升级

1. 增加对低质量轴段的修正 由于三维图纸导出造成某些轴段精度较差&#xff0c;部分管路段的轴线段不满足G1连续&#xff0c;SmartPipe采用算法对这种情况进行了修正&#xff0c;保证轴段在一定精度范围内光滑连续。 2. 优化对中文路径的处理 SmartPipeBatch批处理版本优化…

松灵机器人 scout ros2 驱动 安装

必须使用 ubuntu22 必须使用 链接的humble版本 #打开can 口 sudo modprobe gs_usbsudo ip link set can0 up type can bitrate 500000sudo ip link set can0 up type can bitrate 500000sudo apt install can-utilscandump can0mkdir -p ~/ros2_ws/srccd ~/ros2_ws/src git cl…

路径规划之启发式算法之二十九:鸽群算法(Pigeon-inspired Optimization, PIO)

鸽群算法(Pigeon-inspired Optimization, PIO)是一种基于自然界中鸽子群体行为的智能优化算法,由Duan等人于2014年提出。该算法模拟了鸽子在飞行过程中利用地标、太阳和磁场等导航机制的行为,具有简单、高效和易于实现的特点,适用于解决连续优化问题。 更多的仿生群体算法…

【leetcode练习·二叉树拓展】快速排序详解及应用

本文参考labuladong算法笔记[拓展&#xff1a;快速排序详解及应用 | labuladong 的算法笔记] 1、算法思路 首先我们看一下快速排序的代码框架&#xff1a; def sort(nums: List[int], lo: int, hi: int):if lo > hi:return# 对 nums[lo..hi] 进行切分# 使得 nums[lo..p-1]…