chapter8:SpringBoot启动配置原理

news2024/11/15 21:58:29

尚硅谷SpringBoot顶尖教程

1. 启动流程简介

SpringBoot应用从主启动类启动后的运行流程主要包含下面几个要点:

(1)准备环境

  • 执行ApplicationContextInitializer#initialize()方法;
  • 监听器SpringApplicationRunListener回调contextPrepared方法
  • 加载主配置类定义信息
  • 监听器SpringApplicationRunListener回调contextLoaded方法;

(2)刷新启动IOC容器

  • 扫描加载所有容器中的组件;
  • 包括从META-INF/spring.factories文件中获取的所有EnableAutoConfiguration组件;

(3)回调容器中所有的ApplicationRunner,CommandLineRunner的run方法;

(4)监听器SpringApplicationRunListener回调finished方法

下面来看详细的启动流程分析, 课程讲解使用的是 1.5.10.RELEASE版本的SpringBoot源码。

2. 启动流程源码分析

2.1 创建SpringApplication对象

主启动类的main方法是Springboot应用启动的入口。

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

通过SpringApplication.run方法会进行SpringApplication对象的创建及部分初始化工作。

public class SpringApplication {
    // ...省略非核心代码
    // 主启动类入口调用的run方法
	public static ConfigurableApplicationContext run(Object source, String... args) {
		return run(new Object[] { source }, args);
	}
	
    // 继续走重载的run方法
	public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
		// 第一步:调用SpringApplication构造方法实例化对象
        // 第二步:创建SpringApplication对象后,继续调用重载的run方法
        return new SpringApplication(sources).run(args);
	}	

    // SpringApplication构造方法
	public SpringApplication(Object... sources) {
        // 初始化,参数是springboot应用的主启动类class对象
		initialize(sources);
	}
	
    // 初始化
	private void initialize(Object[] sources) {
        // 保存主配置类到this.sources属性中
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
        // 判断当前springBoot应用是否是一个web应用,并保存判断结果到this.webEnvironment属性中
		this.webEnvironment = deduceWebEnvironment();
        // 从类路径下找到META-INF/spring.factories文件中配置的所有ApplicationContextInitializer并保存到this.initializers属性中。
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
        // 从类路径下找到META-INF/spring.factories文件中配置的所有ApplicationListener并保存到this.listeners属性中
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 从多个配置类中找到有main方法的主配置类,比如:SpringBoot02ConfigApplication
		this.mainApplicationClass = deduceMainApplicationClass();
	}
    
	// 判断当前springBoot应用是否是一个web应用 
    private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };
    
	private boolean deduceWebEnvironment() {
		for (String className : WEB_ENVIRONMENT_CLASSES) {
            // 判断当前环境是否存在ConfigurableWebApplicationContext
			if (!ClassUtils.isPresent(className, null)) {
				return false;
			}
		}
		return true;
	}
	// 保存ApplicationContextInitializer到this.initializers属性中
	public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
		this.initializers.addAll(initializers);
	}
	// 保存ApplicationListener到this.listeners属性中
	public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
		this.listeners = new ArrayList<ApplicationListener<?>>();
		this.listeners.addAll(listeners);
	}
	
	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

    // 从META-INF/spring.factories文件中查找ApplicationContextInitializer.class,ApplicationListener.class
	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
            // META-INF/spring.factories 
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 实例化ApplicationContextInitializer,ApplicationListener
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
}
	// 从多个配置类中找到有main方法的主配置类,比如:SpringBoot02ConfigApplication
	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
                // 通过当前的栈中找到有main方法的配置类,就是主启动类
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

spring-boot-1.5.10.RELEASE.jar!/META-INF/spring.factories文件配置了类的全限定名称;

# 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.context.embedded.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.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

当然类路径下还有其他spring.factories文件都有可能配置的有要初始化的组件类名称,自定义spring.factories也可以。比如: 1.5.10.RELEASE\spring-boot-autoconfigure-1.5.10.RELEASE.jar!\META-INF\spring.factories中的初始化配置。

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

2.2 运行run方法

运行run方法继续完善IOC容器内容,源码分析如下:

public class SpringApplication {
    // ... 
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
        // 配置IOC容器开始
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		configureHeadlessProperty();
        // 从类路径下/META-INF/spring.factories,获取SpringApplicationRunListener
		SpringApplicationRunListeners listeners = getRunListeners(args);
        // 调用所有的SpringApplicationRunListener#starting方法
		listeners.starting();
		try {
            // 封装命令行参数,主启动类main方法的args参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            // 准备环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
            // 打印banner图标
			Banner printedBanner = printBanner(environment);
            // 创建IOC容器, 里面决定创建Web的IOC容器还是普通IOC容器。
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);
            // 准备上下文环境,将environment保存到ioc容器中;
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            // 刷新IOC容器及初始化
			refreshContext(context);
            // IOC容器初始化完成后
			afterRefresh(context, applicationArguments);
            // 所有的SpringApplicationRunListener回调finished()方法
			listeners.finished(context, null);
            // 配置IOC容器结束
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
            //整个SpringBoot应用启动完成后返回启动的IOC容器
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
    
    // 从类路径下/META-INF/spring.factories,获取SpringApplicationRunListeners
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // /META-INF/spring.factories
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
    
    // type=SpringApplicationRunListener
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
            // /META-INF/spring.factories
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 创建SpringApplicationRunListener实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
        // 返回SpringApplicationRunListener实例
		return instances;
	}
    
    // 调用所有的SpringApplicationRunListener#starting方法
    public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}
	
    // 准备环境
	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 创建环境完成后调用所有的SpringApplicationRunListener#environmentPrepared方法,表示环境准备完成。
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}
	//调用所有的SpringApplicationRunListener#environmentPrepared方法,表示环境准备完成。
	public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}
	
    // 嵌入式WEB环境的IOC容器
    public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
    // 普通IOC容器
    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";
    // 创建IOC容器	
    protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			// 创建web的IOC容器,还是普通的IOC容器
			contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
		}
        // 返回实例化的IOC容器
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}
    // 准备上下文环境,将environment保存到ioc容器中;
	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
        // 将environment保存到ioc容器中
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
        // 回调之前保存的所有ApplicationContextInitializer#initialize(context)方法
		applyInitializers(context);
        // 回调之前保存的所有SpringApplicationRunListener#contextPrepared(context)方法
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
        // 回调所有的SpringApplicationRunListener#contextLoaded(context)方法
		listeners.contextLoaded(context);
	}
	// 回调之前保存的所有的ApplicationContextInitializer#initialize(context)方法
	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            // ApplicationContextInitializer#initialize(context)
			initializer.initialize(context);
		}
	}
	// 回调之前保存的所有SpringApplicationRunListener#contextPrepared(context)方法
	public void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
            // SpringApplicationRunListener#contextPrepared(context),表示IOC容器准备完成
			listener.contextPrepared(context);
		}
	}
	// 回调所有的SpringApplicationRunListener#contextLoaded(context)方法
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
            //SpringApplicationRunListener#contextLoaded(context), 表示IOC容器加载完成
			listener.contextLoaded(context);
		}
	}
    
    private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
    //刷新IOC容器
    protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        //扫描、创建、加载IOC容器中的所有组件(配置类,组件,自动配置)。如果是web环境,还会创建嵌入式tomcat容器。
		((AbstractApplicationContext) applicationContext).refresh();
	}
	// IOC容器初始化完成后
	protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
        //从IOC容器中获取所有的ApplicationRunner和CommandLineRunner进行回调。
		callRunners(context, args);
	}

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
                 //从IOC容器中获取所有的ApplicationRunner进行回调。
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
                 //从IOC容器中获取所有的CommandLineRunner进行回调。
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

	private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
            //回调ApplicationRunner#run
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}

	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
            //回调CommandLineRunner#run
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}
	
	// 所有的SpringApplicationRunListener回调finished()方法
	public void finished(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFinishedListener(listener, context, exception);
		}
	}

	private void callFinishedListener(SpringApplicationRunListener listener,
			ConfigurableApplicationContext context, Throwable exception) {
		// 回调SpringApplicationRunListener#finished
		listener.finished(context, exception);
	}
    // ...
}

我们来看运行run方法的debug过程:

从类路径下/META-INF/spring.factories,获取SpringApplicationRunListener
在这里插入图片描述
spring-boot-1.5.10.RELEASE.jar!\META-INF\spring.factories文件中的配置
在这里插入图片描述
debug调试结果:
在这里插入图片描述
回调所有的获取SpringApplicationRunListeners.starting方法
在这里插入图片描述
封装命令行参数:
在这里插入图片描述
准备创建环境,创建环境完成后回调SpringApplicationRunListener#environmentPrepared(environment)方法表示环境准备完成。
在这里插入图片描述
创建ApplicationContext容器,
在这里插入图片描述
里面决定创建Web的IOC容器还是普通IOC容器。
在这里插入图片描述
准备上下文环境,将environment保存到ioc容器中
在这里插入图片描述
applyInitializers(context) 回调之前保存的所有的ApplicationContextInitializer的initialize(context)方法
在这里插入图片描述
回调所有之前保存的SpringApplicationRunListener的contextPrepared(context)方法
在这里插入图片描述
prepareContext(…)方法运行完成后回调所有的SpringApplicationRunListener的contextLoaded(context)方法
在这里插入图片描述
刷新容器,IOC容器初始化,扫描、创建、加载IOC容器中的所有组件(配置类,组件,自动配置)。如果是web环境,还会创建嵌入式tomcat容器。
在这里插入图片描述
IOC容器初始化完成后,web应用(嵌入式tomcat)也已经启动完成。
在这里插入图片描述
从IOC容器中获取所有的ApplicationRunner和CommandLineRunner进行回调。ApplicationRunner先回调,CommandLineRunner后回调。
在这里插入图片描述
所有的SpringApplicationRunListener回调finished方法
在这里插入图片描述
整个SpringBoot应用启动完成后返回启动的IOC容器
在这里插入图片描述

2.3 自定义回调配置

主要看几个重要的事件回调机制 :

ApplicationContextInitializer, SpringApplicationRunListener配置在spring-boot-1.5.10.RELEASE.jar!/META-INF/spring.factories文件中;如果自定义xxxListener, 需要将自定义xxxListener或xxxInitializer放在当前应用类路径下的/META-INF/spring.factories文件中。

自定义ApplicationContextInitializer

public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  @Override
  public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("HelloApplicationContextInitializer.initialize....." + configurableApplicationContext.getClass().getSimpleName());
    }
}

自定义SpringApplicationRunListener

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {

    public HelloSpringApplicationRunListener(SpringApplication application, 
                                             String[] args) {
    }

    // 开始ioc配置
    @Override
    public void starting() {
        System.out.println("HelloSpringApplicationRunListener.starting.....");
    }

    // 准备环境
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        Map<String, Object> systemProperties = environment.getSystemProperties();
        System.out.println("HelloSpringApplicationRunListener.environmentPrepared...," + systemProperties.get("os.name")
                + ',' + systemProperties.get("java.home"));
    }

    // ioc容器准备
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("HelloSpringApplicationRunListener.contextPrepared.....");
    }

    // ioc容器加载
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("HelloSpringApplicationRunListener.contextLoaded.....");
    }

    // ioc容器配置完成
    @Override
    public void finished(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("HelloSpringApplicationRunListener.finished....");
    }
}

将自定义的ApplicationContextInitializer, SpringApplicationRunListener配置在当前项目类路径下的/META-INF/spring.factories文件中

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
com.atgugui.listener.HelloApplicationContextInitializer
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
com.atgugui.listener.HelloSpringApplicationRunListener

ApplicationRunner,CommandLineRunner组件只要放在IOC容器中就可以了;自定义xxxRunner,类上面加@Component即可.

/**
 * ApplicationRunner在IOC容器初始化过程中的SpringApplicationRunListeners#finished中执行
 */
@Component
public class HelloApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("HelloApplicationRunner.run.....");
    }
}

/**
 * CommandLineRunner在IOC容器初始化过程中的SpringApplicationRunListeners#finished中执行
 */
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("HelloCommandLineRunner.run..." + Arrays.asList(args));
    }
}

配置完成,启动应用,查看启动日志,和上面分析的源码执行顺序一样。

HelloSpringApplicationRunListener.starting 开始初始化
HelloSpringApplicationRunListener.environmentPrepared 准备环境

HelloApplicationContextInitializer.initialize方法初始化;

HelloSpringApplicationRunListener.contextPrepared方法准备上下文环境;

HelloSpringApplicationRunListener.contextLoaded方法加载上下文环境;

HelloSpringApplicationRunListener.finished方法上下文环境准备完成。
在这里插入图片描述

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

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

相关文章

ADC 读取电位器旋钮,用回差消除临界值档位跳动

就是比如&#xff0c;用电位器当旋钮做风扇调速&#xff0c;划分出10 个速度档位&#xff0c;对应10 个ADC 转换结果的阈值。如果直接比较阈值&#xff0c;当旋钮拧到临近阈值的地方时&#xff0c;ADC 结果的微小跳动会导致风扇档位在两个级别之间不停左右横跳&#xff0c;因此…

Linux MySQL 索引 事务 存储引擎 死锁

索引&#xff08;面试问得多&#xff09; 索引是一个排序的列表&#xff0c;包含索引字段的值和其相对应的行数据所在的物理地址 作用 加快表的查询速度&#xff0c;还可以对字段排序 如何实现的搜索加速&#xff1f; 没有索引的情况下&#xff0c;要查询某行数据&#xff0c;需…

代码审计——命令执行详解

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 漏洞描述02 审计要点03 漏洞特征04 漏洞案例05 修复方案 01 漏洞描述 命令注入是指因为系统使用了可以执行命令的危险函数&#xff0c;但是调用这些函数的参数可控&#xff0c;并没有做过滤或过滤不…

Flutter集成Umeng步骤及若干问题总结

由于Flutter项目中用到umeng统计及手机号一键登录功能&#xff0c;但实际集成使用中遇到各种坑&#xff0c;文档及demo却都没有提及&#xff0c;因此写下这篇文章&#xff0c;有遇到同样问题的同学可以参考下。 集成之前&#xff0c;最好先查看一下文档&#xff1a;https://de…

LangChain for LLM Application Development 基于LangChain开发大语言应用模型(上)

以下内容均整理来自deeplearning.ai的同名课程 Location 课程访问地址 DLAI - Learning Platform Beta (deeplearning.ai) 一、什么是LangChain 1、LangChain介绍 LangChain是一个框架&#xff0c;用于开发由大语言模型驱动的应用程序。开发者相信&#xff0c;最强大的、差异…

Ubuntu+Pycharm+QtDesigner,并配置Pyqt5

1. 安装PyQt5 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5 2. 安装ubuntu环境下所需要的依赖包 sudo apt install pyqt5* 3. 安装QtDesigner sudo apt install qttools5-dev-tools 4. 设置Pycharm 步骤&#xff1a; File–>setting–>Tools–&…

ESP32设备驱动-VCNL4040趋近传感器

VCNL4040趋近传感器 文章目录 VCNL4040趋近传感器1、VNCL4040介绍2、硬件准备3、软件准备4、驱动实现1、VNCL4040介绍 VCNL4040 将趋近传感器 (PS)、环境光传感器 (ALS) 和高功率 IRED 集成到一个小型封装中。它通过CMOS工艺将光电二极管、放大器和模数转换电路集成到一个芯片…

Linux->线程库接口

目录 前言&#xff1a; 1 进程和线程 2 线程库接口 2.1 线程库基础理解 2.2 创建线程 2.2 线程资源回收 2.3 线程分离 前言&#xff1a; 本篇主要是对Linux原装线程库的函数接口进行学习&#xff0c;还有一部分的线程概念补充。 1 进程和线程 博主在上一篇文章当中有讲过…

中北大学 - 信息对抗大三下学习课程设计(爬取招标网站,进行招标分析,数据保存execl中)

文章目录 1. 题目描述2. 项目细节分析定时爬取任务思路避免多次爬取数据重复问题网站结构根据爬取信息确认招标地区 3. 项目代码4. 运行截图 1. 题目描述 中北大学信息安全技术爬虫课程设计 题目 5&#xff1a;招投标信息分析系统 &#xff08;20050441 2005031113&#xff09…

Floyd算法图解,C++实现Floyd算法

Floyd算法简介 Floyd算法是一种多源最短路径算法&#xff0c;是利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法&#xff0c;与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特弗洛伊德命名。 时间复杂度&am…

Python模块multiprocessing 实现多进程并发

简介 multiprocessing模块是Python标准库中提供的一个用于实现多进程编程的模块。它基于进程而不是线程&#xff0c;可以利用多核CPU的优势&#xff0c;提高程序的执行效率&#xff0c;同时也可以实现进程间通信和数据共享。 目录 1. 参数说明 1.1. Process&#xff08;控制进…

推荐系统初谈

文章目录 简介推荐系统与搜索引擎发展历史所属领域 推荐系统分类概览基于内容的推荐基于协同过滤的推荐基于内存的协同过滤基于模型的协同过滤基于矩阵分解的推荐 推荐系统的评价指标推荐系统存在的问题参考文献 简介 21年笔记迁移&#xff0c;主要介绍了推荐系统的定义、发展…

【IC设计】ICC1 workshop lab guide 学习笔记

文章目录 Lab1 Data Setup&Basic Flow1.1 Create a Milkyway library1.2 Load the Netlist,TLU,Constraints and Controls1.3 Basic Flow:Design Planning1.4 Bsic Flow:Placement1.5 Basic Flow:CTS1.6 Basic Flow:Routing Design Planning2.1 Load the Design2.2 Initial…

算法刷题-字符串-反转字符串II

简单的反转还不够&#xff0c;我要花式反转 541. 反转字符串II 力扣题目链接 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起, 每计数至 2k 个字符&#xff0c;就反转这 2k 个字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。 …

C++笔记之初始化线程的所有方法

code review! C笔记之初始化线程的所有方法 文章目录 C笔记之初始化线程的所有方法一.非类中初始化线程1.使用函数指针初始化线程2.lambda表达式初始化线程3.使用成员函数初始化线程4.使用函数对象(Functor)初始化线程5.使用std::bind绑定函数及其参数初始化线程 二.类中初始化…

滤波电容计算举例

例&#xff1a;输入电压220VAC&#xff0c;功率4W&#xff1b;要求输出电压波动不超过5%&#xff0c;试计算滤波电容容量。 解&#xff1a;&#xff08;1&#xff09;电容的储能公式为&#xff1a;Wc1/2CU^2 当电容充电到峰值电压&#xff08;即220x1.414310V&#xff09;时&am…

数仓的分层理论

一、简介 2021-4-25 11:04:16 数据仓库分层是数据仓库设计中非常重要的一个环节&#xff0c;一个好的分层设计可以极大地简化数据仓库的操作&#xff0c;提升使用体验。然需要注意的是&#xff0c;分层理论并不绝对&#xff0c;只是提供一种普适的指导思想和原则&#xff0c;…

[Spring Cloud]:Study Notes·壹

文章目录 摘要1 认识微服务1.1 单体架构与分布式架构1.2 分布式架构与微服务1.3 微服务架构 2 nacos2.1 什么是nacos2.2 nacos使用2.2.1 nacos使用逻辑2.2.2 启动下载好的nacos2.2.3 引入依赖2.2.4 各注册服务中配置nacos相关信息2.2.5 测试nacos注册成功 3 Ribbon负载均衡3.1 …

改进YOLO系列 | YOLOv5/v7 引入谷歌 Lion 优化器

论文地址:https://arxiv.org/pdf/2302.06675.pdf 代码地址:https://github.com/google/automl/tree/master/lion 我们提出了一种将算法发现作为程序搜索的方法,并将其应用于发现用于深度神经网络训练的优化算法。我们利用高效的搜索技术来探索一个无限且稀疏的程序空间。为了…

计算机视觉-语义分割: FCN DeepLab Unet

文章目录 1. 概要1.1 什么是语义分割1.2 语义分割作用1.3 全卷积网络1.4 反卷积1.5 上采样三种方式1.6 跳层结构 Skip Layer 2. FCN架构3. DeepLab-v13.1 改进点3.2 空洞卷积(Atrous/Dilated convolution) 4. U-Net参考 1. 概要 1.1 什么是语义分割 从像素水平上理解、识别图…