Springboot自定义starter注入到第三方项目IOC容器里

一 Bean扫描

Springboot项目,我们不加@ComponentScan注解,但是也能扫描到@Controller、@Service标记的类,为什么呢?关键在于启动类的@SpringBootApplication注解,该注解由以下三个注解组成:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

可以看到,已经默认有了@ComponentScan注解,但是我们没指定扫描路径,那它是怎么扫描到我们自定义的@Controller、@Service的呢?是因为它会默认扫描添加了该注解的类所在的包及其子包,也就是默认扫描启动类所在的包及启动类所在包的子包。

如果我们就想扫描不是启动类所在包以及子包下的目录,那么需要在启动类加@ComponentScan注解,并且指定要扫描的路径

@ComponentScan(basePackages = "com.example.controller")

总结:Springboot默认只能扫描到启动类所在的包以及该包下的子包,想要扫描其他路径的包,需要加@ComponentScan注解并指定包路径。

二 Bean注册

一般,我们在类上加下边这四个注解,就可以把该类对象注册到IOC容器里了

注解说明位置
@Component声明bean的基础注解不属于以下三类时,就用此注解
@Controller@Component的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解标注在数据访问类上(DAO层,用于与mybatis等整合,用的少)

如果要注册的bean对象来自于第三方(即,不是自定义的类),是无法用 @Component 及其衍生注解声明bean的,Springboot提供了两个注解解决这个问题:@Bean和@Import

如,自己通过maven制作了一个jar包,名字叫common-pojo-1.0-SNAPSHOT.jar,这个jar包里有两个类:Country.java、Province.java

首先通过maven install命令把该jar包安装到本地仓库,maven install命令如下

# -Dfile后的参数换成自己的jar包所在的位置
mvn install:install-file -Dfile=C:\Users\Administrator\Desktop\common-pojo-2.0-SNAPSHOT.jar -DgroupId=cn.myt -DartifactId=common-pojo -Dversion=2.0 -Dpackaging=jar

在这里插入图片描述

或者在idea右侧,找到install,双击即可
在这里插入图片描述

在自己项目里通过maven坐标引入该jar包。接下来,我们注册这个jar包里的bean对象

2.1 方式一:在启动类注册第三方bean对象

在启动类添加方法,返回这个对象,且方法上加@Bean注解。一般不推荐使用这种方式,因为启动类只负责启动即可,推荐使用2.2章节里的方法注册第三方bean

启动类里注册bean对象
验证是否注册成功
在这里插入图片描述

看到控制台有这个对象了,说明注册成功
在这里插入图片描述

2.2 方式二:在配置类里集中注册第三方bean

定义Config类,在类上加@Configuration注解,然后在类里声明和上边一样的方法即可。@Bean可以指定对象名字,如@Bean(“myname”),不指定的话,对象默认的名字是方法名。
在这里插入图片描述

注意:Config类需要放到启动类所在包以及该包的子包下,能被扫描到才行。

如果我们注册的bean对象,需要依赖IOC容器里的已经存在的其他bean对象,那么就需要在注册时,参数上加上需要依赖的对象即可
在这里插入图片描述

2.3 方式三:在启动类加@Import(Xxx.class)注解

这种方式,一般常用的是以下两种场景:

  1. 配置类
  2. ImportSelector 接口实现类

导入配置类

如2.2章节里的Config配置类,如果不在启动类所在包以及子包下的话,就可以通过在启动类加@Import导入
在这里插入图片描述

如果多个配置类的话,Import写数组即可
在这里插入图片描述

导入ImportSelector 接口实现类

首先需要新建一个类实现ImportSelector 接口,然后重写selectImports方法,方法里返回要扫描的类的全类名即可,然后这些类的bean对象就可以注入到IOC容器里了
在这里插入图片描述

启动类里扫描上边这个类

在这里插入图片描述

2.4 注册条件

SpringBoot提供了设置注册生效条件的注解 @Conditional,这个注解用起来不方便,Springboot提供了该注解的衍生注解来使用,如下边这三注解

注解说明
@ConditionalOnProperty配置文件中存在对应的属性,才声明该bean
@ConditionalOnMissingBean当IOC容器里不存在当前类型的bean1时,才声明该bean2
@ConditionalOnClass当前环境存在指定的这个类1时,才声明该bean

@ConditionalOnProperty用法

配置文件添加配置

在这里插入图片描述

然后在注入类Config里的方法上,加上@ConditionalOnProperty注解,此时,如果配置文件里找不到@ConditionalOnProperty里的参数的话,就不会自动注入了

在这里插入图片描述

@ConditionalOnMissingBean用法

在这里插入图片描述

@ConditionalOnClass用法

在这里插入图片描述

三 自动配置原理

自动配置:遵循约定大约配置的原则,在SpringBoot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器。

很显然,上边注入对象的方式,并不是自动的,比如我们使用mybatis时,只要引入依赖后,可以不需要写一堆配置类就能使用相关的对象(即引入依赖后就自动注入了),而我们上边注入的对象,还需要手动写配置类。

源码分析

程序引入spring-boot-starter-web 起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet。要验证IOC里是否有DispatcherServlet对象,在启动类里打印一下即可(不添加starter-web启动依赖):

在这里插入图片描述

上边的项目里加上web启动依赖,就不会报错了,因为此时就自动注入了DispatcherServlet对象,再次运行结果如下

在这里插入图片描述

那Springboot是如何做到,添加了web依赖后就自动注入DispatcherServlet对象的呢?此时我们来看源码,首先进入启动类的@SpringBootApplication注解里,就能看到@EnableAutoConfiguration注解(自动配置的核心注解)…依次按照下图进入

在这里插入图片描述

找到AutoConfigurationImportSelector类里的selectImports方法,之前说过,selectImports方法会被Springboot自动调用,从而得到全类名的字符串数组,然后把这些类的bean对象注入到IOC容器里(由于AutoConfigurationImportSelector是间接实现ImportSelector接口,Springboot实际没走这里的selectImports方法,但是注入原理是一样的)

此处的selectImports方法,和上边讲解的一样,需要读取配置文件去找自动配置的类,那读取的是哪个配置文件呢?跟踪源码,会找到,它读取的是:

在这里插入图片描述

注意,springboot2.7之后读取的是上边的文件,2.7版本之前,读取的是META-INF/spring.factories文件

我们开始在pom.xml里引入了web依赖,点进去看
在这里插入图片描述
进去后,可以看到引用了auto-config依赖

在这里插入图片描述

在左侧找到这个jar包,展开后,就能看到这个jar包里提供了Springboot所需的自动注入的配置文件了。打开这个配置文件,里边配置的就是一些类的全类名,如下

在这里插入图片描述

其中,有一个就是我们要找的DispatcherServletAutoConfiguration类全路径

在这里插入图片描述

进入这个类里

在这里插入图片描述
发现,和我们自己注入的bean逻辑一样。

自定义jar包里的对象实现自动注入

那么,我们之前自定义包里的Country.java类,怎么实现自动注入呢?自定义的包,在打包前,按照以下四部走即可(第四章节有具体实战)

在这里插入图片描述

  1. 自己打的jar包里,需要有CommonConfig.java类
  2. 新建自动配置类,并且该类上需要添加俩注解@AutoConfiguration、@Import,其中@AutoConfiguration表明该类是配置类,@Import用来把配置类导入进来
  3. 提供.imports文件
  4. 把自动配置文件的全类名写入上边的imports文件里

按照上边的步骤,打包后如下,并通过pom.xml引入到我们的新Springboot项目里:

在这里插入图片描述

在新项目里引入jar包后,在启动类里获取Country或者Province的bean对象,看是否能获取到

在这里插入图片描述

可以看到,获取到了Province的bean对象,说明已经自动注入成功了。此时,启动类上的@Import也就不需要了,因为可以自动配置了。

说一说SpringBoot自动配置原理

  1. 在主启动类上添加了SpringBootApplication注解, 这个注解组合了EnableAutoConfiguration注解
  2. EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类
  3. 实现selectImports方法, 这个方法经过层层调用,最终会读取META-INF 目录下的 后缀名 为imorts的文件,当然了,boot2.7以前的版本,读取的是spring.factories文件(boot2.7~3.0,这俩文件都支持,boot3.0后只支持import文件)
  4. 读取到全类名了之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中

四 自定义Starter

在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot 的 starter。

我们创建一个maven工程,该工程下新建俩子模块,分别是autoconfigure、starter模块,这俩模块作用为:

  1. autoconfigure 模块,提供自动配置功能,并自定义配置文件 META-INF/spring/xxx.imports(Springboot2.7之前是META-INF/spring.factories,本文使用的Springboot版本是2.5.15)
  2. starter模块,需要在starter模块里引入上边的自动配置模块,以后在第三方项目引入starter模块即可

4.1 新建一个工程

在这里插入图片描述

新建后,把src目录删除,然后新建俩子模块

在这里插入图片描述

在此工程基础上需要新建两个子模块,一个是autoconfigure模块,另一个是starter模块

在这里插入图片描述

新建后的俩模块如下

在这里插入图片描述

其中,my-starter模块,只保留pom.xml,其他什么都不需要。

4.2 父工程

pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>mysdk</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><name>mysdk</name><description>mysdk</description><modules><module>my-autoconfigure</module><module>my-starter</module></modules><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.5.15</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>

4.3 autoconfigure模块

pom.xml引入自动配置的依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency>
</dependencies>
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><skip>true</skip></configuration></plugin></plugins>
</build>

定义MyProperties.java类,用于获取第三方项目配置文件里的动态值

import org.springframework.boot.context.properties.ConfigurationProperties;/*** @Author:sgw* @Date:2024/1/19* @Description: 用于获取第三方项目,配置文件里的值* 指定项目在属性文件中配置的前缀为sgw,如 sgw.str1=test1 ,就可以改变属性类字段 str1 的值了*/
@SuppressWarnings("ConfigurationProperties")
@ConfigurationProperties(prefix = "sgw")
public class MyProperties {public static final String DEFAULT_STR1 = "default value1";public static final String DEFAULT_STR2 = "default value2";private String str1 = DEFAULT_STR1;private String str2 = DEFAULT_STR2;public String getStr1() {return str1;}public void setStr1(String str1) {this.str1 = str1;}public String getStr2() {return str2;}public void setStr2(String str2) {this.str2 = str2;}
}

定义MyTestService业务类,处理数据

import org.springframework.stereotype.Service;/*** @Author:sgw* @Date:2024/1/18* @Description: 业务类,处理数据,包括处理MyProperties里获取到的配置文件里的数据*/
@Service
public class MyTestService {private String str1;private String str2;public String getStr1() {return str1;}public void setStr1(String str1) {this.str1 = str1;}public String getStr2() {return str2;}public void setStr2(String str2) {this.str2 = str2;}public String myTest1() {String name1 = "我的测试1数据是:" + str1;String name2 = "我的测试2数据是:" + str2;System.out.println(name1);System.out.println(name2);return name1 + name2;}
}

定义MyAutoConfig自动配置类,将业务类自动装配注入到第三方的IOC容器里,这样第三方项目就可以自动注入MyTestService了

import com.sge.properties.MyProperties;
import com.sge.service.impl.MyTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author:sgw* @Date:2024/1/19* @Description: 注入IOC容器配置类*/
// 定义 java 配置类
@Configuration
//引入Service,这里是数组,可以注入多个Service
@ConditionalOnClass({MyTestService.class})
// 将 application.properties 的相关的属性字段与该类一一对应,并生成 Bean
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfig {// 注入属性类@Autowiredprivate MyProperties myProperties;@Bean// 当容器没有这个 Bean 的时候才创建这个 Bean@ConditionalOnMissingBean(MyTestService.class)public MyTestService testService() {MyTestService myTestService = new MyTestService();myTestService.setStr1(myProperties.getStr1());myTestService.setStr2(myProperties.getStr2());myTestService.myTest1();return myTestService;}
}

如果这个类需要注册过滤器或者需要注入多个service,参考下边

package com.zkts.fd.fd_register_server.config;import com.zkts.fd.fd_register_server.mapper.UsersMapper;
import com.zkts.fd.fd_register_server.service.UsersService;
import com.zkts.fd.fd_register_server.service.impl.UsersServiceImpl;
import com.zkts.fd.fd_register_server.token.*;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** @Author:sgw* @Date:2024/7/4* @Description:*/
@Configuration
@MapperScan("com.zkts.fd.fd_register_server.mapper")public class UserdetailServiceAutoConfiguration {@Beanpublic UserDetailsService userDetailsService() {return new UserDetailsServiceImpl();}@Bean@ConditionalOnMissingBean(UsersService.class)public UsersService usersService() {return new UsersServiceImpl();}// 当容器没有这个 Bean 的时候才创建这个 Bean// @ConditionalOnMissingBean(SysPasswordService.class)@Beanpublic SysPasswordService passwordService() {return new SysPasswordService();}@ConditionalOnMissingBean(GlobalExceptionHandler.class)public GlobalExceptionHandler globalExceptionHandler() {return new GlobalExceptionHandler();}//@ConditionalOnMissingBean(RedisCache.class)@Beanpublic RedisCache redisCache() {return new RedisCache();}@Beanpublic AuthenticationEntryPointImpl unauthorizedHandler() {return new AuthenticationEntryPointImpl();}//@Beanpublic LogoutSuccessHandler logoutSuccessHandler() {return new LogoutSuccessHandlerImpl();}@Beanpublic JwtAuthenticationTokenFilter authenticationTokenFilter() {return new JwtAuthenticationTokenFilter();}@Bean@ConditionalOnMissingBean(CorsFilter.class)public CorsFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();// 设置允许访问的源(* 表示允许任何源)config.addAllowedOriginPattern("*");// 设置允许的请求方法config.addAllowedMethod("*");// 设置允许的头信息config.addAllowedHeader("*");// 是否允许携带Cookieconfig.setAllowCredentials(true);// 添加映射路径,可以是特定路径或所有路径UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config); // ** 表示对所有路径生效return new CorsFilter(source);}//@ConditionalOnMissingBean(TokenService.class)@Beanpublic TokenService tokenService() {return new TokenService();}@Beanpublic PermitAllUrlProperties permitAllUrl() {return new PermitAllUrlProperties();}
}

在resource目录下定义META-INF/spring.factories文件,内容如下

# Auto Configure,后边的值是自动配置类全路径
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sge.config.MyAutoConfig

如果这个文件里需要写多个类的话,参考下边

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zkts.fd.fd_register_server.token.SecurityConfig,\
com.zkts.fd.fd_register_server.config.UserdetailServiceAutoConfiguration,\
com.zkts.fd.fd_register_server.token.GlobalExceptionHandler

上边这个文件,是帮助第三方项目扫描自动配置类路径的,扫描后将其注入到IOC容器里

4.4 starter模块

starter模块只有一个功能,就是引入上边autoconfigure模块即可,所以starter模块的pom.xml如下

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.example</groupId><artifactId>my-autoconfigure</artifactId><version>0.0.1-SNAPSHOT</version></dependency>
</dependencies>

4.5 打包上传到maven仓库

注意,此处,install打包上传时,要打最外层父项目的maven

在这里插入图片描述

4.6 在第三方项目引入依赖使用上边的业务类

第三方项目引入上边的starter依赖即可

 <dependency><groupId>org.example</groupId><artifactId>my-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

然后注入MyTestService并调用相关方法

@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate MyTestService myTestService;@GetMapping("/list")public R<List<UserEntity>> userList() {String s = myTestService.myTest1();return s;}
}

注意,此时,第三方项目还没有在配置文件里配置sgw为前缀的值,我们调用接口,看结果如下

在这里插入图片描述

可以看到,此时获取到的结果值,是MyProperties里定义的常量值。

我们在第三方项目里配置上sgw为前缀的值,如下

在这里插入图片描述

此时,再访问接口,获取到的结果值如下

在这里插入图片描述

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

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

相关文章

关于BSV区块链覆盖网络的常见问题解答(下篇)

​​发表时间&#xff1a;2024年9月20日 在BSV区块链上的覆盖网络服务为寻求可扩展、安全、高效交易处理解决方案的开发者和企业家开辟了新的视野。 作为开创性的曼达拉升级的一部分&#xff0c;覆盖网络服务提供了一个强大的框架&#xff0c;用于管理特定类型的交易和数据访问…

如何将 html 渲染后的节点传递给后端?

问题 现在我有一个动态的 html 节点&#xff0c;我想用 vue 渲染后&#xff0c;传递给后端保存 思路 本来想给html的&#xff0c;发现样式是个问题 在一个是打印成pdf&#xff0c;然后上传&#xff0c;这个操作就变多了 最后的思路是通过 html2canvas 转化成 canvas 然后变成…

XUbuntu安装OpenSSH远程连接服务器

目录 打开终端。更新你的包索引安装OpenSSH服务器。在终端中输入以下命令&#xff1a;安装完成后&#xff0c;OpenSSH服务器会自动启动。查看主机 IP测试连接打开 cmd 终端SSH 连接虚拟机确认连接输入连接密码发现问题修改用户&#xff0c;尝试连接 打开终端。 更新你的包索引 …

在 Android 上恢复已删除文件的 5 种简单方法

您可能会因为意外删除、未完成的 Android 更新、手机意外关机等原因而丢失 Android 上的重要数据。新技术的发展使许多手机功能或程序能够从内部恢复丢失的数据。 在 Android 上恢复已删除文件的 5 种简单方法 然而恢复成功率的不确定性也成为人们克服数据丢失困境的重要考虑因…

安卓13禁止锁屏 关闭锁屏 android13禁止锁屏 关闭锁屏

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 设置 =》安全 =》屏幕锁定 =》 无。 我们通过修改系统屏幕锁定配置,来达到设置屏幕不锁屏的配置。像网上好多文章都只写了在哪里改,改什么东西,但是实际上并未写明为什么要改那…

鸿蒙NEXT开发-面试题库(最新)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

SQL Server 2022 RTM Cumulative Update #15 发布下载

SQL Server 2022 RTM Cumulative Update #15 发布下载 最新的累积更新 (CU) 下载&#xff0c;包含自 SQL Server 2022 RTM 发布以来的所有更新。 请访问原文链接&#xff1a;https://sysin.org/blog/sql-server-2022/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留…

物联网智能项目(含案例说明)

物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;智能项目是指利用物联网技术将各种物理设备、传感器、软件、网络等连接起来&#xff0c;实现设备之间的互联互通&#xff0c;并通过数据采集、传输、处理和分析&#xff0c;实现智能化管理和控制的项目。以…

ARM嵌入式学习--第二天

-指令流水线 -基础知识 1.流水线技术通过多个功能部件并行工作来缩短程序执行时间&#xff0c;提高处理器的效率和吞吐率 2.增加流水线级数&#xff0c;可以简化流水线的各级逻辑&#xff0c;进一步提高了处理器的性能 3.以三级流水线分析&#xff1a; pc代表程序计数器&#x…

如何用ChatGPT 8小时写出一篇完整论文(附完整提示词)

今天教大家如何利用ChatGPT完成一篇完整的论文。只需要一个标题&#xff0c;剩下全部由ChatGPT完成。总耗时8小时。 阅前提醒&#xff1a; 1.适用人群&#xff1a;这个方法适合应付简单的学术任务&#xff0c;比如日常小论文或投稿一般期刊。但如果你要写高水平的论文&#xf…

漏洞挖掘 | 通过错误日志实现XXE外带

介绍 在最近的一个项目中&#xff0c;我发现了一个与 XML 外部实体&#xff08;XXE&#xff09;攻击相关的重大安全问题。 本文讲述了我在项目中发现并利用 XXE 漏洞的过程&#xff0c;特别是通过一种非传统的方式——利用 Java 异常在日志文件中输出攻击结果。 什么是XXE&a…

AIGC时代的程序员生存法则:如何在AI辅助编程工具普及的背景下保持并提升核心竞争力

随着AIGC&#xff08;AI-Generated Content&#xff0c;如ChatGPT、MidJourney、Claude等&#xff09;技术的迅猛发展&#xff0c;特别是大型语言模型的不断涌现&#xff0c;程序员的工作方式正发生深刻变革。AI辅助编程工具的普及给编程行业带来了前所未有的挑战和机遇。一方面…

Android Framework禁用手势上滑及按钮进多任务的功能

安卓手势多任务 安卓手势多任务是指在安卓系统中&#xff0c;通过特定的手势操作来实现多任务管理的功能。 以下是一些常见的安卓手势多任务操作&#xff1a; 从屏幕底部上滑&#xff1a;这是最常见的安卓手势多任务操作之一。在大多数安卓手机上&#xff0c;从屏幕底部向上滑…

STM32 DMA直接存储器访问 USART串口DMA发送 F407寄存器

DMA介绍&#xff1a; 特点&#xff1a; DMA:直接存储器访问 用于外设与存储器间以及存储器与存储器之间 提高数据传输的一种工具&#xff08;片上外设&#xff09; CPU相当于餐厅老板&#xff0c;只需要告诉DMA快递员 …

DAY8 Final等

Final关键字 final修饰静态变量&#xff0c;这个变量今后被称为常量&#xff0c; 可以记住一个固定值&#xff0c;并且程序中不能修改了&#xff0c;通常这个值作为系统的配置信息。常量的名称&#xff0c;建议全部大写&#xff0c;多个单词用下划线连接。 public static final…

模拟信号的光调制

怎么通过光来传输模拟信号&#xff1f; 模拟信号的光调制是指将模拟信号转换为光信号&#xff0c;并通过调制光信号的强度、频率或相位等参数&#xff0c;将模拟信号信息叠加到光信号中以实现传输和接收。调制的方式分为内调制和外调制。 一 内调制 激光的内调制是指在激光形成…

睿考网:24年中级经济师考试安排

睿考网为大家介绍一下中级经济师考试安排及注意事项 1、考点分布原则 中级经济师考试遵循属地化管理原则&#xff0c;通常在各地级市以上的城市设立考点。考生应在工作所在地或户口所在地报名参加考试&#xff0c;具体考点由计算机系统随机编排确定。 2、考试时间安排 2024…

关于摩托车一键启动无钥匙进入、智能科技创新

摩托车一键启动无钥匙进入功能 一、工作原理 摩托车的一键启动无钥匙进入功能采用了世界最先进的RFID无线射频技术和最先进的车辆身份编码识别系统&#xff0c;率先应用小型化、小功率射频天线的开发方案&#xff0c;并成功融合了遥控系统和无钥匙系统&#xff0c;沿用了传统…

二手跨境电商Mecari注册运营策略总结

热门电商平台如Meicari&#xff08;煤炉&#xff09;近几年在跨境中非常火爆。然而&#xff0c;对于国内卖家来说&#xff0c;要成功在Meicari平台上运营&#xff0c;不仅需要优质的商品和服务&#xff0c;还需要稳定而可靠的网络支持。 一、静态IP是什么&#xff1f; Meicari…

数字产业中心:优化资源配置与提升产业效率

在数字化浪潮席卷全球的今天&#xff0c;数字产业中心作为新时代的产物&#xff0c;正以其独特的魅力和无限的潜力&#xff0c;引领着产业转型升级的新方向。数字产业中心&#xff0c;通过深度整合数字技术与实体经济&#xff0c;不仅优化了资源配置&#xff0c;还极大地提升了…