【spring boot starter的自定义和学习笔记】

spring boot starter的自定义和理解

author:shengfq
date:2024-07-14
version:1.0
title:spring boot starter的自定义和理解

1.基本概念

Starter是Spring Boot的四大核心功能特性之一,除此之外,Spring Boot还有自动装配、Actuator监控等特性。
Spring Boot Starter是Spring Boot项目中的一个重要概念,它是一组方便的依赖描述符,可以简化项目配置和依赖管理。通过引入特定的Starter,开发者可以快速地将相关的依赖项添加到项目中,而无需手动配置每个依赖项。
此外,Spring Boot Starter还遵循“约定优于配置”的原则,通过自动配置来减少手动配置的工作量。这意味着,只要项目中存在特定的类、资源或依赖项,Spring Boot就会自动应用相关的配置。

2.Spring Boot Starter的主要特点

简化依赖管理:通过引入Starter,开发者无需手动添加和管理大量的依赖项,降低了配置错误的概率。
约定优于配置:Starter遵循“约定优于配置”的原则,通过默认的配置满足大多数场景的需求,减少了手动配置的工作量。调用者可以最简化配置本地属性.
自动配置:Spring Boot会根据classpath下的类、资源文件和META-INF/spring.factories配置文件自动配置项目所需的各种组件和服务。
易于扩展,快速集成:开发者可以通过自定义Starter来扩展Spring Boot的功能,满足特定项目的需求。提供组件或插件/客户端服务.

3.Spring Boot Starter的应用场景

1.Web应用开发: 通过引入spring-boot-starter-web,开发者可以快速搭建基于Spring MVC的Web应用程序。
2.数据访问层开发: 使用spring-boot-starter-data-jpa或spring-boot-starter-jdbc等Starter,可以简化与关系型数据库的交互。
3.消息队列集成: 通过spring-boot-starter-amqp等Starter,可以方便地集成RabbitMQ等消息队列中间件。
4.安全性控制: 引入spring-boot-starter-security,可以为应用程序添加身份验证、授权等安全功能。
5.微服务架构: 在构建微服务时,可以利用Spring Cloud提供的各种Starter来实现服务发现、配置管理、熔断降级等功能。

4.Spring Boot Starter的实现原理

Spring Boot Starter的原理主要涉及两个方面:起步依赖(起步依赖其实就是将具备某种功能的坐标打包到一起,从而可以简化依赖导入的过程)和自动配置(通过自动配置来减少手动配置的工作量)。

起步依赖:每个Starter都定义了一组相关的依赖项,这些依赖项被打包在一起形成一个独立的模块。当开发者在项目中引入某个Starter时,构建工具会自动解析并下载该模块及其依赖项。
自动配置机制:Spring Boot在启动时会自动扫描classpath下的类、资源文件和META-INF/spring.factories配置文件。这些文件中定义了各种自动配置类,每个自动配置类都包含了一些条件和注解,用于判断是否需要自动配置相应的组件和服务。如果满足条件,Spring Boot就会自动创建并配置这些组件和服务。
配置文件的加载:Spring Boot会默认加载classpath下的application.properties或application.yml配置文件,开发者可以在这些文件中提供自定义的配置属性来覆盖默认配置。此外,Spring Boot还支持通过命令行参数、环境变量等方式提供配置属性。
扩展性支持:开发者可以通过创建自定义的Starter来扩展Spring Boot的功能。自定义Starter需要包含相应的依赖项和自动配置类,并遵循Spring Boot的命名规范和文件结构。然后,将自定义Starter发布到Maven中央仓库或其他仓库中,供其他项目使用。
具体来说,当项目中存在某个Starter时,Spring Boot会读取该Starter中的META-INF/spring.factories文件,该文件定义了该Starter所提供的自动配置类。然后,Spring Boot会根据这些自动配置类中的条件和注解来自动配置相关的组件和服务。例如,如果项目中存在spring-boot-starter-web这个Starter,那么Spring Boot就会自动配置Spring MVC和嵌入式Tomcat等Web相关的组件和服务。

此外,Spring Boot的自动配置还遵循“约定优于配置”的原则,即尽可能使用默认的配置来满足大多数情况的需求,从而进一步减少了手动配置的工作量。如果开发者需要自定义某些配置,可以通过在application.properties或application.yml文件中提供相应的属性值来实现。

总的来说,Spring Boot Starter的原理是通过定义起步依赖和自动配置来简化项目的构建和配置过程。这使得开发者能够更专注于业务逻辑的实现,而无需花费大量时间在繁琐的配置和依赖管理上。

5.生产实践

5.1 自定义starter的步骤
5.1.1 为什么要创建自定义Starter?
虽然Spring Boot提供了许多开箱即用的Starter,但在某些情况下,你可能希望创建自己的Starter来封装你的库、服务或特定的配置逻辑。自定义Starter可以:
将模块功能代码从服务中拆出来作为组件,其他服务可以复用组件功能,无需关注组件具体实现过程,也是
封装思想的提现.

5.1.2 创建自定义Spring Boot Starter的步骤

设置Maven或Gradle项目:
首先,你需要创建一个新的Maven或Gradle项目来构建你的Starter。在项目的pom.xml(对于Maven)或build.gradle(对于Gradle)文件中,添加必要的Spring Boot依赖项和插件。

定义自动配置类:
创建一个带有@Configuration注解的Java类,该类将包含你的Starter提供的所有bean定义和默认配置。你可以使用@Bean注解来定义bean,并使用@ConditionalOn…注解来指定bean的创建条件(例如,当某个类在类路径中可用时)。

打包和发布:
将你的Starter打包为一个JAR文件,并将其发布到Maven中央仓库或其他可用的Maven仓库中。这样,其他项目就可以通过添加对你的Starter的依赖来使用它了。
创建spring.factories文件:在src/main/resources/META-INF目录下创建一个名为spring.factories的文件,并指定你的自动配置类的全限定名。这个文件是Spring Boot在启动时查找自动配置类的地方。

测试你的Starter:
创建一个简单的Spring Boot应用程序来测试你的Starter。通过注入你的Starter提供的bean来验证它们是否按预期工作。你还可以编写单元测试和集成测试来确保你的Starter在各种条件下都能正常工作。

文档和支持:
为你的Starter提供清晰的文档和示例代码,以帮助其他开发者了解如何使用它。
使用自定义Spring Boot Starter
一旦你的自定义Starter被打包并发布到Maven仓库中,其他项目就可以通过在其pom.xml或build.gradle文件中添加对你的Starter的依赖来使用它了。然后,这些项目将能够自动获得你的Starter提供的所有依赖项和默认配置。如果需要的话,它们还可以通过提供自己的配置来覆盖你的Starter的默认配置。

5.1.3 自定义Spring Boot Starter案例
下面是一个创建自定义Spring Boot Starter的案例。我们创建一个名为ftp-spring-boot-starter的Starter(官方推荐命名:spring-boot-starter-xxx),该Starter将提供一个简单的服务来记录和管理应用程序中的事件。

首先,我们需要创建一个新的Maven项目,并在pom.xml文件中定义必要的依赖项和构建配置。

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>ftp-spring-boot-starter</artifactId><version>1.0.0</version><packaging>jar</packaging><name>ftp-spring-boot-starter</name><description>ftp-spring-boot-starter</description><properties><java.version>1.8</java.version><spring-boot.version>2.6.13</spring-boot.version> </properties><dependencies><!-- Spring Boot Dependencies --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${spring-boot.version}</version></dependency><!-- Other Dependencies --><!-- Add any other dependencies your starter might need --></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin></plugins></build>
</project>

接下来,我们创建自动配置类FtpAutoConfiguration,该类将包含我们的服务的默认配置和bean定义。


@Configuration
@EnableConfigurationProperties(FtpClientProperties.class)
@ConditionalOnClass(FtpClientTemplate.class)
@ConditionalOnProperty(prefix = "ftp.client", value = "enabled", matchIfMissing = true)
public class FtpAutoConfiguration {private final FtpClientProperties properties;public FtpAutoConfiguration(FtpClientProperties properties) {this.properties = properties;}@Bean@ConditionalOnMissingBeanpublic FtpClientFactory ftpClientFactory() {return new FtpClientFactory(properties);}@Bean@ConditionalOnMissingBeanpublic FtpClientTemplate ftpClientTemplate(FtpClientFactory ftpClientFactory) {return new FtpClientTemplate(ftpClientFactory);}
}

然后,我们定义FtpClientTemplate(操作API接口)和FtpClientFactory(连接池化)


package com.coctrl.ftp.service;import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;import javax.annotation.PreDestroy;import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.util.ObjectUtils;import com.coctrl.ftp.CommonException;import lombok.extern.slf4j.Slf4j;@Slf4j
public class FtpClientTemplate {public final String ROOT_PATH = File.separator + "domestic2" + File.separator + "xxx";private final GenericObjectPool<FTPSClient> ftpClientPool;private FtpClientFactory ftpClientFactory;public FtpClientTemplate(FtpClientFactory ftpClientFactory) {this.ftpClientPool = new GenericObjectPool<>(ftpClientFactory);this.ftpClientPool.setTestOnBorrow(true);this.ftpClientFactory = ftpClientFactory;}@PreDestroypublic void destroy() {this.ftpClientPool.close();}/**** 上传Ftp文件** @param localFile 当地文件内容* @param remotePath 上传服务器路径 - 应该以/结束* @return true or false*/public boolean uploadFile(byte[] localFile, String remotePath, String fileName) {if (localFile == null) {log.error("上传文件字节为空");return false;}FTPSClient ftpClient = null;BufferedInputStream inStream = null;boolean upload = false;try {// 从池中获取对象ftpClient = ftpClientFactory.create();// 验证FTP服务器是否登录成功int replyCode = ftpClient.getReplyCode();if (!FTPReply.isPositiveCompletion(replyCode)) {log.warn("ftpServer refused connection, replyCode:{}", replyCode);throw new CommonException("登录FTP服务器失败");}// 改变工作路径// ftpClient.changeWorkingDirectory(remotePath);boolean makeDirectory = ftpClient.makeDirectory(remotePath);if (makeDirectory) {log.info("路径创建成功 {}", remotePath);} else {log.info("路径已存在,直接使用 {}", remotePath);}ftpClient.changeWorkingDirectory(remotePath);inStream = new BufferedInputStream(new ByteArrayInputStream(localFile));log.info("start upload... {}", fileName);upload = ftpClient.storeFile(fileName, inStream);log.info("upload file success! {}", fileName);} catch (Exception e) {log.error("upload file failure!", e);throw new CommonException("上传文件失败");} finally {if (inStream != null) {try {inStream.close();} catch (IOException e) {log.error("输入流关闭失败", e);}}// 将对象放回池中destroy(ftpClient);}return upload;}/*** 下载文件** @param remotePath FTP服务器文件目录* @param fileName 需要下载的文件名称* @return true or false*/public byte[] downloadFile(String remotePath, String fileName) {FTPSClient ftpClient = null;byte[] fileByte = null;try {ftpClient = ftpClientFactory.create();// 切换FTP目录FTPFile[] ftpFiles = ftpClient.listFiles(remotePath);for (FTPFile file : ftpFiles) {if (fileName.equals(file.getName())) {/** fileByte = IOUtils.toByteArray(ftpClient.retrieveFileStream(remotePath + "/" +* file.getName()));*/break;}}if (ObjectUtils.isEmpty(fileByte)) {throw new CommonException("未找到对应的文件,请联系管理员");}return fileByte;} catch (Exception e) {log.error("download file failure!", e);throw new CommonException(e);} finally {destroy(ftpClient);}}/*** 获取文件大小** @param remotePath FTP服务器文件目录* @param fileName 需要下载的文件名称* @return true or false*/public Long getFileSize(String remotePath, String fileName) {FTPSClient ftpClient = null;try {ftpClient = ftpClientFactory.create();// 切换FTP目录FTPFile[] ftpFiles = ftpClient.listFiles(remotePath);for (FTPFile file : ftpFiles) {if (fileName.equals(file.getName())) {return file.getSize();}}return 0L;} catch (Exception e) {log.error("download file failure!", e);throw new CommonException(e);} finally {destroy(ftpClient);}}private void destroy(FTPClient ftpClient) {if (ftpClient == null) {return;}try {ftpClient.logout();} catch (IOException io) {log.error("ftp client logout failed...{}", io);} finally {try {if (ftpClient.isConnected()) {ftpClient.disconnect();}} catch (IOException io) {log.error("close ftp client failed...{}", io);}}}public String getRemotePath(String remotePath) {remotePath = ROOT_PATH + File.separator + remotePath;return remotePath;}}package com.coctrl.ftp.service;import java.io.IOException;import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.apache.commons.net.util.TrustManagerUtils;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import com.coctrl.ftp.configuration.FtpClientProperties;import lombok.extern.slf4j.Slf4j;@Slf4j
@ConditionalOnProperty(prefix = "ftp.client", value = "enabled", matchIfMissing = true)
public class FtpClientFactory extends BasePooledObjectFactory<FTPSClient> {private FtpClientProperties config;public FtpClientFactory(FtpClientProperties config) {this.config = config;}/*** 创建FtpClient对象*/@Overridepublic FTPSClient create() {FTPSClient ftpClient = new FTPSClient();ftpClient.setControlEncoding(config.getEncoding());// ftpClient.setDataTimeout(config.getDataTimeout());// ftpClient.setConnectTimeout(config.getConnectTimeout());// ftpClient.setControlKeepAliveTimeout(config.getKeepAliveTimeout());ftpClient.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());// 必须设置此属性,通过TSL加密连接try {ftpClient.connect(config.getHost(), config.getPort());int replyCode = ftpClient.getReplyCode();if (!FTPReply.isPositiveCompletion(replyCode)) {ftpClient.disconnect();log.warn("ftpServer refused connection,replyCode:{}", replyCode);return null;}if (!ftpClient.login(config.getUsername(), config.getPassword())) {log.warn("ftpClient login failed... username is {}; password: {}", config.getUsername(),config.getPassword());}ftpClient.changeWorkingDirectory(config.getPath());ftpClient.setBufferSize(config.getBufferSize());ftpClient.setFileType(FTP.BINARY_FILE_TYPE);if (config.isPassiveMode()) {ftpClient.enterLocalPassiveMode();}ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);ftpClient.execPROT("P");} catch (IOException e) {log.error("create ftp connection failed...", e);}return ftpClient;}/*** 用PooledObject封装对象放入池中*/@Overridepublic PooledObject<FTPSClient> wrap(FTPSClient ftpClient) {return new DefaultPooledObject<>(ftpClient);}/*** 销毁FtpClient对象*/@Overridepublic void destroyObject(PooledObject<FTPSClient> ftpPooled) {if (ftpPooled == null) {return;}FTPClient ftpClient = ftpPooled.getObject();try {ftpClient.logout();} catch (IOException io) {log.error("ftp client logout failed...{}", io);} finally {try {if (ftpClient.isConnected()) {ftpClient.disconnect();}} catch (IOException io) {log.error("close ftp client failed...{}", io);}}}/*** 验证FtpClient对象*/@Overridepublic boolean validateObject(PooledObject<FTPSClient> ftpPooled) {try {FTPClient ftpClient = ftpPooled.getObject();if (!ftpClient.sendNoOp()) {return false;}// 验证FTP服务器是否登录成功int replyCode = ftpClient.getReplyCode();if (!FTPReply.isPositiveCompletion(replyCode)) {log.warn("ftpServer refused connection, replyCode:{}", replyCode);return false;}return true;} catch (IOException e) {log.error("failed to validate client: {}", e);}return false;}
}

为了使我们的Starter能够被Spring Boot的自动配置机制识别,我们需要在src/main/resources/META-INF目录下创建一个spring.factories文件,并添加以下配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.coctrl.ftp.configuration.FtpAutoConfiguration

这告诉Spring Boot在启动时查找FtpAutoConfiguration类,并根据其中的条件自动配置beans。

现在,我们已经创建了一个简单的自定义Spring Boot Starter。要将其打包并安装到本地Maven仓库中,请在项目根目录下运行以下命令:

mvn clean install

一旦安装完成,其他项目就可以通过在其pom.xml文件中添加以下依赖来使用这个Starter了:


<dependency><groupId>com.coctrl</groupId><artifactId>ftp-spring-boot-starter</artifactId><version>1.0.0.RELEASE</version>
</dependency>

在使用此Starter的项目中,开发者可以通过注入FtpClientTemplate来访问FTP客户端方法,而无需关心如何配置或实现该服务。这就是Spring Boot Starter的强大之处——它提供了可插拔的组件和预配置的默认值,从而加速了开发过程。

5.2.相关注解说明

类注解
@Configuration注解
@ConditionalOnClass
@EnableConfigurationProperties方法注解
@Bean注解 将组件或插件的实例在容器启动时,声明加入到容器Context中,例如声明一个Exchange,Bing,Queue.
@ConditionalOnMissingBean注解 条件加载注解,只有满足实例bean未被加载时才加载.spring.factories
Spring的SPI机制介绍
其实是SpringBoot提供的SPI机制,底层实现是基于SpringFactoriesLoader检索ClassLoader中所有jar(包括ClassPath下的所有模块)引入的META-INF/spring.factories文件,基于文件中的接口(或者注解)加载对应的实现类并且注册到IOC容器。这种方式对于@ComponentScan不能扫描到的并且想自动注册到IOC容器的使用场景十分合适,基本上绝大多数第三方组件甚至部分spring-projects中编写的组件都是使用这种方案

6.我的理解

1.starter的2个基本特性,启动自动化配置(预配置)和依赖自动化(预配置),适合于服务客户端组件和插件做自动化集成,用户无需关心依赖的组件配置.
2.软件产品:组件/插件/框架/工程/系统.spring-boot-starter是软件组件制作的框架.mybatis是ORM框架,spring-boot-starter-mybatis是官方提供的快速集成组件,mybatis-plus是基于mybatis实现的更接近应用层的插件.
3.starter的实现原理,还是依赖springboot官方提供的SPI机制,开发者感兴趣可以深究,这是实现组件化的基本原理.

7.常用的官方提供的starter

一些常用的Spring Boot Starter包括:
spring-boot-starter:这是Spring Boot的核心启动器,包含了自动配置、日志和YAML等基础设施。
spring-boot-starter-web:用于构建Web应用程序,提供了Spring MVC和嵌入式Tomcat等Web技术。
spring-boot-starter-data-jpa:用于简化Spring Data JPA的配置和使用,提供了与关系型数据库交互的能力。
spring-boot-starter-test:用于单元测试和集成测试,包含了JUnit、Mockito等测试框架和库。
spring-boot-starter-security:用于提供应用程序的安全性,包括身份验证、授权等功能。
企业级的starter:
spring-boot-starter-amqp 用于支持AMQP协议的消息队列
spring-boot-starter-mail 用于发送电子邮件

二. spring-boot-plugin 插件的引入

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin></plugins></build>

附录.spring-boot-starter-parent

spring-boot-starter-parent 是 Spring Boot 提供的一个父 POM(Project Object Model),它简化了 Maven 或 Gradle 构建配置,为开发者提供了默认的依赖管理、插件配置以及一些最佳实践设置。当你创建一个新的 Spring Boot 项目时,通常会继承这个父 POM。在官方文档中,有一个章节介绍了如何管理依赖项,其中就包含了对 spring-boot-starter-parent 的介绍。
相关章节标题:《Managing dependencies with the starter parent POM》
该章节详细解释了为什么使用 spring-boot-starter-parent,以及它如何帮助管理你的项目依赖和版本。尽管 spring-boot-starter-parent 主要关注 依赖管理和构建配置 ,但文档中也有一些章节提到了如何定制自动配置,这可能间接与父 POM 的使用相关联。<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.6.RELEASE</version>
</parent>
<groupId>org.hzero</groupId>
<artifactId>hzero-parent</artifactId>
<version>1.5.0.RELEASE</version>
<packaging>pom</packaging>mvn dependency:tree
maven工程继承结构
spring-boot-starter-parenthzero-parenthzero-boot-parent

三.参考文档

深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter

Spring Boot Maven plugin 官方文档

SpringBoot 自动化配置官方文档

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

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

相关文章

顺序表算法 - 移除元素

. - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/remove-element/description/思路: 代码: // numsSize表示数组的长度 …

【2024年全国青少信息素养大赛c++初中复赛集训第一天编程题分享】

目录 题目 1:星际旅行者的紧急求助 题目 2:失落的文明遗迹 题目 3:时间之门的密码 题目5,输出多进制数 题目6、乒乓球 题目7、明明的随机数 题目8、烤鸡 题目9、排队接水 题目 10:魔法森林的迷宫 题目 11:校园植树节活动 题目 12:小学生数学竞赛排名 题目 1:…

力扣224.基本计算器

力扣224.基本计算器 一个栈存符号 并记录当前数的符号遍历到一个数就存入答案 class Solution {public:int calculate(string s) {stack<int> st({1});int sign 1;int res0;int number;int n s.size();int i0;while(i<n) {if(isdigit(s[i])){number 0;while(i &…

python+pygame实现五子棋人机对战之五

pythonpygame实现五子棋人机对战之一 pythonpygame实现五子棋人机对战之二 pythonpygame实现五子棋人机对战之三 pythonpygame实现五子棋人机对战之四 在之前的文章中已经完成了所有的基础工作&#xff0c;剩下的就是把空填上就可以了。 六、 完成程序 # encoding:utf-8…

网络安全——防御课实验二

在实验一的基础上&#xff0c;完成7-11题 拓扑图 7、办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 首先&#xff0c;按照之前的操作&#xff0c;创建新的安全区&#xff08;电信和移动&#xff09;分别表示两个外网…

Readiris PDF Corporate / Business v23 解锁版安装教程 (PDF管理软件)

前言 Readiris PDF Corporate / Business 是一款高性能的 OCR&#xff08;光学字符识别&#xff09;软件&#xff0c;能够帮助用户将纸质文档、PDF 文件或图像文件转换为可编辑和可搜索的电子文本。该软件提供专业级的功能和特性&#xff0c;非常适合企业和商业使用。使用 Rea…

基于lstm的股票Volume预测

LSTM&#xff08;Long Short-Term Memory&#xff09;神经网络模型是一种特殊的循环神经网络&#xff08;RNN&#xff09;&#xff0c;它在处理长期依赖关系方面表现出色&#xff0c;尤其适用于时间序列预测、自然语言处理&#xff08;NLP&#xff09;和语音识别等领域。以下是…

LabVIEW人工模拟肺控制系统开发

开发了一种创新的主被动一体式人工模拟肺模型&#xff0c;通过LabVIEW开发的上位机软件&#xff0c;实现了步进电机驱动系统的精确控制和多种呼吸模式的模拟。该系统不仅能够在主动呼吸模式下精确模拟快速呼吸、平静呼吸和深度呼吸&#xff0c;还能在被动模式下通过PID控制实现…

2024.07.06校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、校招 | 网易游戏雷火2025届秋季校园招聘/全/球启动&#xff08;内推&#xff09; 校招 | 网易游戏雷火2025届秋季校园招聘全球启动&#xff08;内推&#xff09; 2、芯之所向 共创未来…

Taro自定义FromData实现本地路径转换为文件

在用Taro写头像上传功能时&#xff0c;因为需要对获得的图片进行剪切成圆形或方形。使用组件剪切完之后返回的是一个本地图片的相对路径。这个时候我们就需要自己实现将本地路径重新转换为二进制文件。 引入两个js文件 mimeMap.js module.exports {"0.001": &quo…

C++20中的consteval说明符

在C20中&#xff0c;立即函数(immediate function)是指每次调用该函数都会直接或间接产生编译时常量表达式(constant expression)的函数。这些函数在其返回类型前使用consteval关键字进行声明。 立即函数是constexpr函数&#xff0c;具体情况取决于其要求。与constexpr相同&…

神经网络以及简单的神经网络模型实现

神经网络基本概念&#xff1a; 神经元&#xff08;Neuron&#xff09;&#xff1a; 神经网络的基本单元&#xff0c;接收输入&#xff0c;应用权重并通过激活函数生成输出。 层&#xff08;Layer&#xff09;&#xff1a; 神经网络由多层神经元组成。常见的层包括输入层、隐藏层…

Tomcat(42)如何在Tomcat中实现基于角色的访问控制?

在Tomcat中实现基于角色的访问控制&#xff08;Role-Based Access Control, RBAC&#xff09;涉及配置用户角色和安全约束&#xff0c;以确保只有授权的用户可以访问特定的资源。以下是在Tomcat中实现RBAC的详细步骤&#xff0c;包括代码示例。 1. 配置用户和角色 首先&#…

算法刷题笔记 合并集合(C++实现)

文章目录 题目描述基本思路实现代码 题目描述 一共有n个数&#xff0c;编号是1∼n&#xff0c;最开始每个数各自在一个集合中。现在要进行m个操作&#xff0c;操作共有两种&#xff1a; M a b&#xff0c;将编号为a和b的两个数所在的集合合并&#xff0c;如果两个数已经在同一…

springboot健身房预约管理系统-计算机毕业设计源码75535

目录 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.1.1经济可行性 2.1.2技术可行性 2.1.3操作可行性 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 …

Gradle学习-6 APT 实现一个路由跳转框架(APT、发布maven仓库)

Annotation 注解&#xff1a;注解是元数据&#xff0c;即描述数据的数据APT&#xff08;Annotation Processing Tool&#xff09;注解处理器 APT工作原理 Demo介绍 APT项目地址 使用APT maven仓库地址 &#xff08;1&#xff09;项目配置 Gradle 8.2AGP 8.2.0Java jdk 17…

调整网络安全策略以适应不断升级的威胁形势

关键网络安全统计数据和趋势 当今数字时代网络安全的重要性

Tensor-LLM简单介绍

最近体验了一下英伟达的TensorRT-LLM的最新版本&#xff0c;写个简单介绍&#xff0c;给大家参考。 TensorRT-LLM是专门用于大语言模型推理和部署的产品&#xff0c;同类型产品还有来自UC-Berkley的vLLM,上海人工实验室的LMDeploy&#xff0c;英特尔的OpenVINO。 英特尔的Ope…

【工具推荐】高效查看日志利器:推荐使用uvviewsoft LogViewer

文章目录 高效查看日志利器&#xff1a;推荐使用uvviewsoft LogViewer什么是uvviewsoft LogViewer&#xff1f;主要功能 uvviewsoft LogViewer 的优势高性能强大的搜索与过滤功能友好的用户界面实时监控 下载和安装安装步骤 使用示例打开日志文件搜索日志内容过滤日志内容实时查…

Python爬虫速成之路(2):爬天气情况

hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命Coding-CSDN博客 &a…