当前位置: 首页 > news >正文

spring cloud config server源码学习(一)

文章目录

  • 1. 注解EnableConfigServer
  • 2. ConfigServerAutoConfiguration
    • 2.1 @ConditionalOnBean和@ConditionalOnProperty
    • 2.2 @Import注解
      • 2.2.1. EnvironmentRepositoryConfiguration.class
      • 2.2.2. CompositeConfiguration.class
      • 2.2.3. ResourceRepositoryConfiguration.class
      • 2.2.4. ConfigServerEncryptionConfiguration.class
      • 2.2.5. ConfigServerMvcConfiguration.class
      • 2.2.6. ResourceEncryptorConfiguration.class
  • 3. EnvironmentRepository
  • 4. EnvironmentRepositoryConfiguration.class
  • 5. rest接口

spring cloud config server 作为一个spring boot工程,到底是如何运行起来的?似乎如上一篇文章中那样,引入了starter,启动了注解,配置了git的信息,就可以获取到数据了。那具体的原理是什么呢?

1. 注解EnableConfigServer

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

可以看到启动类上加入注解@EnableConfigServer。我们查看该注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigServerConfiguration.class)
public @interface EnableConfigServer {}

这个注解的定义当中,通过Import注解加载Bean ConfigServerConfiguration.class

@Configuration(proxyBeanMethods = false)
public class ConfigServerConfiguration {@Beanpublic Marker enableConfigServerMarker() {return new Marker();}class Marker {}}

这个Configuration类只是加载了一个 Bean Marker。
这是spring加载Bean的一种常用方式。

2. ConfigServerAutoConfiguration

在spring cloud config Server的jar中,org.springframework.boot.autoconfigure.AutoConfiguration.imports文件内包含了多个自动配置的类,其中就包括ConfigServerAutoConfiguration类。

org.springframework.cloud.config.server.bootstrap.ConfigServerBootstrapOverridesAutoConfiguration
org.springframework.cloud.config.server.config.ConfigServerAutoConfiguration
org.springframework.cloud.config.server.config.RsaEncryptionAutoConfiguration
org.springframework.cloud.config.server.config.DefaultTextEncryptionAutoConfiguration
org.springframework.cloud.config.server.config.EncryptionAutoConfiguration
org.springframework.cloud.config.server.config.VaultEncryptionAutoConfiguration

根据命名,可以看到各个自动配置类的功能,是启用bootstrap配置还是启用RSA加密等等。这里暂时先关注
ConfigServerAutoConfiguration类:

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
@ConditionalOnProperty(name = ConfigServerProperties.PREFIX + ".enabled", matchIfMissing = true)
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class,ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class,ResourceEncryptorConfiguration.class })
public class ConfigServerAutoConfiguration {}

这个类的注解包含了三个重要的注解@ConditionalOnBean、@ConditionalOnProperty和@Import。

2.1 @ConditionalOnBean和@ConditionalOnProperty

当这两个注解出现在同一个类上的时候,两个Conditional条件必须同时满足,即ConfigServerConfiguration.Marker.class这个Bean存在的同时,还要满足Spring环境属性中存在 ConfigServerProperties.PREFIX + “.enabled” 属性且其值为 true,或者该属性缺失(由于 matchIfMissing = true)。这个PREFIX是spring.cloud.config.server。
这里刚好好上面通过@EnableConfigServer加载的Bean Marker.class呼应上。

2.2 @Import注解

Import注解引入了六个类要加载到spring context中。

2.2.1. EnvironmentRepositoryConfiguration.class

EnvironmentRepositoryConfiguration 是Spring Cloud Config Server中配置存储库的核心配置类。它负责创建和配置EnvironmentRepository实例,EnvironmentRepository用于从各种后端(如Git、SVN、本地文件系统等)获取配置属性。

定义和配置不同类型的EnvironmentRepository(如GitEnvironmentRepository、NativeEnvironmentRepository)。
通过注入不同的配置属性,来灵活配置不同类型的存储库。

2.2.2. CompositeConfiguration.class

CompositeConfiguration 负责配置和管理CompositeEnvironmentRepository。CompositeEnvironmentRepository允许将多个EnvironmentRepository组合在一起,以便从多个源获取配置。

配置CompositeEnvironmentRepository,将多个EnvironmentRepository实例组合成一个逻辑上的存储库。
提供从多个配置源合并配置属性的功能,以实现更复杂的配置管理场景。

2.2.3. ResourceRepositoryConfiguration.class

ResourceRepositoryConfiguration 负责配置与管理资源存储库(ResourceRepository)。ResourceRepository用于访问和管理配置服务器上的静态资源,如配置文件、密钥等。

配置不同类型的ResourceRepository,如文件系统资源存储库或Git资源存储库。
通过REST接口提供资源访问和管理功能。

2.2.4. ConfigServerEncryptionConfiguration.class

ConfigServerEncryptionConfiguration 负责配置加密和解密功能。它提供加密和解密配置属性的能力,确保敏感数据在传输和存储时得到保护。

配置加密器(TextEncryptor),用于加密和解密敏感配置信息。
提供加密和解密端点,允许客户端通过API进行加密和解密操作。

2.2.5. ConfigServerMvcConfiguration.class

ConfigServerMvcConfiguration 配置Spring MVC相关的组件,为Spring Cloud Config Server提供RESTful API。它定义了Config Server的主要控制器和路由。

定义Config Server的REST API端点,处理配置属性的请求。
配置HTTP请求处理、路由和控制器。

2.2.6. ResourceEncryptorConfiguration.class

ResourceEncryptorConfiguration 负责配置与资源加密相关的功能。它确保资源存储库中的敏感数据在存储和访问时得到加密保护。

配置用于资源加密和解密的组件。
提供加密资源的支持,确保静态资源的安全性。

3. EnvironmentRepository

对于 Spring Cloud Config 而言,它把所有的配置信息抽象为一种 Environment(环境),而存储这些配置信息的地方就称为 EnvironmentRepository。

public interface EnvironmentRepository {Environment findOne(String application, String profile, String label);default Environment findOne(String application, String profile, String label, boolean includeOrigin) {return findOne(application, profile, label);}}

spring cloud中把配置信息抽象为application,profile和label三个维度来管理,即哪一个应用application在什么样的环境profile下,使用哪一个label的配置数据。

4. EnvironmentRepositoryConfiguration.class

这个类里加载很多的内容,包括svn、git、jdbc等等的RepositoryConfiguration。其中有一个Configuration类是DefaultRepositoryConfiguration.class。这个是放在最后一个加载的配置,即默认的配置:

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(value = EnvironmentRepository.class, search = SearchStrategy.CURRENT)
class DefaultRepositoryConfiguration {@Beanpublic MultipleJGitEnvironmentRepository defaultEnvironmentRepository(MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,MultipleJGitEnvironmentProperties environmentProperties) throws Exception {return gitEnvironmentRepositoryFactory.build(environmentProperties);}}

这里是加载MultipleJGitEnvironmentRepository的Bean,由gitEnvironmentRepositoryFactory的build方法来构建:

public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties)throws Exception {if (this.connectionFactory.isPresent()) {HttpTransport.setConnectionFactory(this.connectionFactory.get());this.connectionFactory.get().addConfiguration(environmentProperties);}MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment,environmentProperties, ObservationRegistry.NOOP);repository.setTransportConfigCallback(transportConfigCallbackFactory.build(environmentProperties));if (this.server.getDefaultLabel() != null) {repository.setDefaultLabel(this.server.getDefaultLabel());}repository.setGitCredentialsProviderFactory(gitCredentialsProviderFactory);repository.getRepos().forEach((name, repo) -> repo.setGitCredentialsProviderFactory(gitCredentialsProviderFactory));return repository;}

而DefaultRepositoryConfiguration这个类,被GitRepositoryConfiguration继承了。

@Configuration(proxyBeanMethods = false)
@Profile("git")
class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {}

也就是说 Spring Cloud Config 中默认使用 Git 作为配置仓库来完成配置信息的存储和管理,提供的 EnvironmentRepository 就是 MultipleJGitEnvironmentRepository,而 MultipleJGitEnvironmentRepository 则继承了抽象类 JGitEnvironmentRepository。

当服务器启动时,在 JGitEnvironmentRepository 中会决定是否调用 initClonedRepository() 方法来完成从远程 Git 仓库 Clone 代码。如果执行了这一操作,相当于会将配置文件从 Git 上 clone 到本地,然后再进行其他的操作。在 JGitEnvironmentRepository 抽象类中,提供了大量针对第三方 Git 仓库的操作代码,无论采用诸如 Git、SVN 等具体某一种配置仓库的实现方式,最终我们处理的对象都是位于本地文件系统中的配置文件。

请添加图片描述
在AbstractScmEnvironmentRepository类中

@Overridepublic synchronized Environment findOne(String application, String profile, String label) {return findOne(application, profile, label, false);}@Overridepublic synchronized Environment findOne(String application, String profile, String label, boolean includeOrigin) {NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(getEnvironment(),new NativeEnvironmentProperties(), this.observationRegistry);Locations locations = getLocations(application, profile, label);delegate.setSearchLocations(locations.getLocations());Environment result = delegate.findOne(application, profile, "", includeOrigin);result.setVersion(locations.getVersion());result.setLabel(label);return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(), getUri());}

在上面的findOne方法中,调用了NativeEnvironmentRepository类的findOne方法:

@Overridepublic Environment findOne(String config, String profile, String label, boolean includeOrigin) {try {ConfigurableEnvironment environment = getEnvironment(config, profile, label);DefaultResourceLoader resourceLoader = new DefaultResourceLoader();Map<org.springframework.core.env.PropertySource<?>, PropertySourceConfigData> propertySourceToConfigData = new HashMap<>();ConfigDataEnvironmentPostProcessor.applyTo(environment, resourceLoader, null,StringUtils.commaDelimitedListToSet(profile), new ConfigDataEnvironmentUpdateListener() {@Overridepublic void onPropertySourceAdded(org.springframework.core.env.PropertySource<?> propertySource,ConfigDataLocation location, ConfigDataResource resource) {propertySourceToConfigData.put(propertySource,new PropertySourceConfigData(location, resource));}});environment.getPropertySources().remove("config-data-setup");return clean(ObservationEnvironmentRepositoryWrapper.wrap(this.observationRegistry, new PassthruEnvironmentRepository(environment)).findOne(config, profile, label, includeOrigin), propertySourceToConfigData);}catch (Exception e) {String msg = String.format("Could not construct context for config=%s profile=%s label=%s includeOrigin=%b",config, profile, label, includeOrigin);String completeMessage = NestedExceptionUtils.buildMessage(msg,NestedExceptionUtils.getMostSpecificCause(e));throw new FailedToConstructEnvironmentException(completeMessage, e);}}

我们看到最终委托 PassthruEnvironmentRepository 完成配置文件的读取,然后通过 clean 方法完成本地文件地址与远程仓库之间地址的转换。ConfigDataEnvironmentUpdateListener用于监听Environment的更新。

5. rest接口

Server端获取到了数据,是通过rest接口来提供给client的。这里EnvironmentController提供了rest接口:

@GetMapping(path = "/{name}/{profiles:(?!.*\\b\\.(?:ya?ml|properties|json)\\b).*}",produces = MediaType.APPLICATION_JSON_VALUE)public Environment defaultLabel(@PathVariable String name, @PathVariable String profiles) {return getEnvironment(name, profiles, null, false);}@GetMapping(path = "/{name}/{profiles:(?!.*\\b\\.(?:ya?ml|properties|json)\\b).*}",produces = EnvironmentMediaType.V2_JSON)public Environment defaultLabelIncludeOrigin(@PathVariable String name, @PathVariable String profiles) {return getEnvironment(name, profiles, null, true);}@GetMapping(path = "/{name}/{profiles}/{label:.*}", produces = MediaType.APPLICATION_JSON_VALUE)public Environment labelled(@PathVariable String name, @PathVariable String profiles, @PathVariable String label) {return getEnvironment(name, profiles, label, false);}@GetMapping(path = "/{name}/{profiles}/{label:.*}", produces = EnvironmentMediaType.V2_JSON)public Environment labelledIncludeOrigin(@PathVariable String name, @PathVariable String profiles,@PathVariable String label) {return getEnvironment(name, profiles, label, true);}

这里要注意path路径的配置,在类注解上有@RequestMapping(method = RequestMethod.GET, path = “${spring.cloud.config.server.prefix:}”)可以配置前缀,不配置的话就是默认值“”。
在方法上的路径,是/name/profile/label。这个正是配置文件中配置的内容。

相关文章:

spring cloud config server源码学习(一)

文章目录 1. 注解EnableConfigServer2. ConfigServerAutoConfiguration2.1 ConditionalOnBean和ConditionalOnProperty2.2 Import注解2.2.1. EnvironmentRepositoryConfiguration.class2.2.2. CompositeConfiguration.class2.2.3. ResourceRepositoryConfiguration.class2.2.4.…...

人脸识别——探索戴口罩对人脸识别算法的影响

1. 概述 人脸识别是一种机器学习技术&#xff0c;广泛应用于各种领域&#xff0c;包括出入境管制、电子设备安全登录、社区监控、学校考勤管理、工作场所考勤管理和刑事调查。然而&#xff0c;当 COVID-19 引发全球大流行时&#xff0c;戴口罩就成了日常生活中的必需品。广泛使…...

磁盘管理后续——盘符漂移问题解决

之前格式化磁盘安装了文件系统&#xff0c;且对磁盘做了相应的挂载&#xff0c;但是服务器重启后挂载信息可能有问题&#xff0c;或者出现盘符漂移、盘符变化、盘符错乱等故障&#xff0c;具体是dev/sda, sdb, sdc 等等在某些情况下会混乱掉 比如sda变成了sdb或者sdc变成了sdb等…...

基于GO 写的一款 GUI 工具,M3u8视频下载播放器-飞鸟视频助手

M3u8视频下载播放器-飞鸟视频助手 M3u8视频飞鸟视频助手使用m3u8下载m3u8 本地播放 软件下载地址m3u8嗅探 M3u8视频 M3u8视频格式是为网络视频播放设计&#xff0c;视频网站多数采用 m3u8格式。如腾讯&#xff0c;爱奇艺等网站。 m3u8和 mp4的区别&#xff1a; 一个 mp4是一个…...

关于EasyExcel导入数据时表格日期格式识别为数字问题

参考官方地址 自定义日期转字符串转换器 /*** 自定义excel日期转换器** author li* date 2024-05-29*/ public class CustomStringDateConverter implements Converter<String> {Overridepublic Class<?> supportJavaTypeKey() {return String.class;}Overridep…...

高通Android 12/13打开省电模式宏开关

1、添加到SettingsProvider配置项宏开关 默认节电助手自动开启百分比battery saver frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java private void loadGlobalSettings(SQLiteDatabase db) {在该方法中添加 ......final i…...

2023年西安交通大学校赛(E-雪中楼)

E.雪中楼 如果算出按南北的序列&#xff0c;再转成从低到高的编号序列&#xff0c;岂不是太麻烦了&#xff0c;幸好&#xff0c;没有在这方面费长时间&#xff0c;而是意识到&#xff0c;本质就是要从低到高的编号序列&#xff0c;所以我就按样例模拟了一下&#xff0c;当a[i]0…...

如何在vue2中使用tailwind

查看官方文档&#xff0c;不要去看过时的文章&#xff01; 使用官网推荐的第一个安装方法 Installation - Tailwind CSS vue版本&#xff1a;2.6.10 1. 安装tailwind的包 npm install -D tailwindcss npx tailwindcss init 2. tailwind.config.js 文件中的content是你需要…...

【OrangePi AIpro】开箱初体验以及OAK深度相机测试

1. 简介 Orangepi AIPRO 是一款采用昇腾AI技术路线&#xff0c;集成4核64位处理器AI处理器的单板计算机&#xff0c;集成图形处理器&#xff0c;支持8TOPS AI算力&#xff0c;拥有8GB/16GB LPDDR4X&#xff0c;可以外接eMMC模块&#xff0c;支持双4K高清输出。 Orange Pi AIpr…...

滑动窗口模板(Java)

题目描述 有一个长为 &#x1d45b; 的序列 &#x1d44e;&#xff0c;以及一个大小为 &#x1d458; 的窗口。现在这个从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最大值和最小值。 例如&#xff0c;对于序列 [1,3,−1,−3,5,3,6,7] …...

transformers.BertTokenizer入门使用

教程link 示例代码 from transformers import OpenAIGPTLMHeadModel, GPT2LMHeadModel, BertTokenizer import torch tokenizer BertTokenizer.from_pretrained("thu-coai/CDial-GPT_LCCC-large") model OpenAIGPTLMHeadModel.from_pretrained("thu-coai/CD…...

快乐数-力扣

使用一个set来存储遇到的每个数&#xff0c;如果遇到的数在set中&#xff0c;那么说明这个数不是快乐数&#xff0c;否则一直循环下去&#xff0c;直到n 1结束循环&#xff0c;表示这个数是个快乐数。 需要注意的是&#xff0c;给定一个数 n, 怎样对这个数 n 进行每一位求和。…...

Git标签的使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

【uni-app】Pinia 持久化

小程序端 Pinia 持久化 说明&#xff1a;Pinia 用法与 Vue3 项目完全一致&#xff0c;uni-app 项目仅需解决持久化插件兼容性问题。 持久化存储插件 安装持久化存储插件&#xff1a; pinia-plugin-persistedstate pnpm i pinia-plugin-persistedstate插件默认使用 localStor…...

Flink 窗口

窗口&#xff08;Window&#xff09; 窗口是处理无限流的核心。 窗口将流分割成有限大小的“桶”&#xff0c;我们可以计算窗口中的数据。 窗口程序一般有键控流&#xff08;keyed streams&#xff09;的窗口程序 和 非键控流&#xff08;non-keyed streams&#xff09;的窗口…...

基于大模型和RAG技术实现的开源项目

基于大模型和RAG技术实现的开源项目 为解决大模型的不足&#xff0c;使用RAG技术增强大模型生成内容的针对性和可读性能力&#xff0c;有很多不错的开源项目。例如下面的项目。 1 ragflow 优点&#xff1a;可以对文档和知识库进行管理&#xff0c;构建不同的知识库&#xff…...

mac m1安装homebrew管理工具(brew命令)完整流程

背景 因为mac上的brew很久没用了&#xff0c;版本非常旧&#xff0c;随着mac os的更新&#xff0c;本机的homebrew大部分的功能都无法使用&#xff0c;幸好过去通过brew安装的工具比较少&#xff0c;于是决定重新安装一遍brew。 卸载旧版brew 法一&#xff1a;通过使用线上…...

Liunx学习随笔

Linux学习随笔 Linux学习随笔一.前期准备1.安装Vmware Workstation软件2.下载linux镜像3.安装操作系统4.配置静态ip5.下载安装远程连接工具 二.语法2.1 linux哲学思想(原则)2.2 小命令 夕阳无限好&#xff0c;只是近黄昏&#xff0c;时隔一年&#xff0c;重新提笔 没有比脚更远…...

mac中文件夹怎么显示.git隐藏文件

1. 打开终端应用程序&#xff0c;然后进入到包含.git文件夹的目录&#xff0c;可以使用以下命令来显示隐藏文件和文件夹&#xff1a; defaults write com.apple.finder AppleShowAllFiles YES 2. 然后重启 Finder&#xff1a; killall Finder...

【PB案例学习笔记】-13 徒手做个电子时钟

写在前面 这是PB案例学习笔记系列文章的第11篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...