Spring Boot 系统初始化器详解

Spring Boot 3.x系列文章

  1. Spring Boot 2.7.8 中文参考指南(一)
  2. Spring Boot 2.7.8 中文参考指南(二)-Web
  3. Spring Boot 源码阅读初始化环境搭建
  4. Spring Boot 框架整体启动流程详解
  5. Spring Boot 系统初始化器详解

自定义系统初始化器

Spring Boot 有多种加载自定义初始化器的方法:
1、创建一个实现ApplicationContextInitializer接口的类,在spring.factories中添加,如MyInitializer
2、创建一个实现ApplicationContextInitializer接口的类,在SpringApplication 中使用addInitializers添加,如MyInitializer2
3、创建一个实现ApplicationContextInitializer接口的类,在application.ymlapplication.properties中使用context.initializer.classes添加,如MyInitializer3
4、创建一个实现EnvironmentPostProcessor接口的类,在spring.factories中添加,如MyEnvironmentPostProcessor

代码如下所示:

MyInitializer.java


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;import java.util.HashMap;
import java.util.Map;@Slf4j
@Order(2)
public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();Map<String, Object> map = new HashMap<>();map.put("key", "value");MapPropertySource mapPropertySource = new MapPropertySource("mySource", map);configurableEnvironment.getPropertySources().addLast(mapPropertySource);log.info("My Initializer run");}
}

MyInitializer2.java


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;import java.util.HashMap;
import java.util.Map;@Slf4j
@Order(1)
public class MyInitializer2 implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();Map<String, Object> map = new HashMap<>();map.put("key2", "value2");MapPropertySource mapPropertySource = new MapPropertySource("mySource", map);configurableEnvironment.getPropertySources().addLast(mapPropertySource);log.info("My Initializer2 run");}
}

MyInitializer3.java


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;import java.util.HashMap;
import java.util.Map;@Slf4j
@Order(10)
public class MyInitializer3 implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();Map<String, Object> map = new HashMap<>();map.put("key3", "value3");MapPropertySource mapPropertySource = new MapPropertySource("mySource", map);configurableEnvironment.getPropertySources().addLast(mapPropertySource);log.info("My Initializer3 run");}
}

MyEnvironmentPostProcessor.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;import java.util.HashMap;
import java.util.Map;@Slf4j
@Order(5)
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {Map<String, Object> map = new HashMap<>();map.put("key", "value");MapPropertySource mapPropertySource = new MapPropertySource("mySource", map);environment.getPropertySources().addLast(mapPropertySource);//为什么不打印日志
//        log.info("My EnvironmentPostProcessor run");System.out.println("My EnvironmentPostProcessor run");}
}

启动后截图:
在这里插入图片描述

疑问❓

  • 在MyEnvironmentPostProcessor的示例中,用log.info("My EnvironmentPostProcessor run"); 不会打印日志。
  • MyInitializer3的输出怎么会在MyInitializer2之前。

加载原理

实例1加载原理

在之前的文章中《Spring Boot 框架整体启动流程详解》有介绍到Spring Boot 应用程序初始化的时候会从META-INF/spring.factories加载ApplicationContextInitializer类实例

在这里插入图片描述
SpringFactoriesLoader 是Spring 框架中的类,用于从多个Jar文件的META-INF/spring.factories中加载并实例化给定的类型,spring.factories文件必须采用Properties格式,其中key是接口或抽象类的完全限定名称,value是以逗号分隔的实现类名列表。例如:
example.MyService=example.MyServicesImpl1,example.MyService Impl2
其中example.MyService是接口的名称,MyServiceImpl1和MyServiceImpl2是两个实现。

获取实例分成了两部分,首先从多个Jar文件的META-INF/spring.factories中加载key和value,返回一个SpringFactoriesLoader实例,然后调用SpringFactoriesLoader的load方法初始化指定key(key为接口或者抽象类的全限定名)对应的所有value(接口实现类),返回实例列表。

spring.factories的加载

在这里插入图片描述
FACTORIES_RESOURCE_LOCATION指定了加载的路径

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static SpringFactoriesLoader forResourceLocation(String resourceLocation, @Nullable ClassLoader classLoader) {
// 判断资源路径是否为空,若为空则抛出异常Assert.hasText(resourceLocation, "'resourceLocation' must not be empty");
// 获取资源对应的类加载器,若传入的类加载器为空,则使用SpringFactoriesLoader类的类加载器ClassLoader resourceClassLoader = (classLoader != null ? classLoader :SpringFactoriesLoader.class.getClassLoader());
// 从缓存中获取SpringFactoriesLoader,若不存在,则创建一个并缓存 Map<String, SpringFactoriesLoader>,key为ClassLoader,资源对应的类加载器Map<String, SpringFactoriesLoader> loaders = cache.computeIfAbsent(resourceClassLoader, key -> new ConcurrentReferenceHashMap<>());
// 返回resourceLocation对应的SpringFactoriesLoader对象,若不存在,则创建一个并缓存,key为resourceLocation,资源路径return loaders.computeIfAbsent(resourceLocation, key ->new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation)));
}

computeIfAbsent 返回的是key关联的value值

最后一步value创建了一个SpringFactoriesLoader实例,loadFactoriesResource 使用给定的资源类加载器从"META-INF/spring.factories"中加载

protected static Map<String, List<String>> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) {
//实现列表,key=接口或抽象类全限定名 value=实现类全限定名Map<String, List<String>> result = new LinkedHashMap<>();try {//获取指定路径下所有的资源URLEnumeration<URL> urls = classLoader.getResources(resourceLocation);while (urls.hasMoreElements()) {UrlResource resource = new UrlResource(urls.nextElement());//从URL资源中读取配置Properties properties = PropertiesLoaderUtils.loadProperties(resource);properties.forEach((name, value) -> {//实现类逗号分割,转换为数组String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) value);//接口的实现类列表List<String> implementations = result.computeIfAbsent(((String) name).trim(),key -> new ArrayList<>(factoryImplementationNames.length));//去掉实现类两边空格,并插入实现类列表Arrays.stream(factoryImplementationNames).map(String::trim).forEach(implementations::add);});}//去重
result.replaceAll(SpringFactoriesLoader::toDistinctUnmodifiableList);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" + resourceLocation + "]", ex);}//返回不可修改的mapreturn Collections.unmodifiableMap(result);
}

加载部分有很多的key,value 要分清楚。

spring.factories接口实现类的实例化

实例化通过调用SpringFactoriesLoader的load方法

	public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver) {return load(factoryType, argumentResolver, null);}

factoryType指定要实例化的类型,这里为 org.springframework.context.ApplicationContextInitializer
argumentResolver 实例化需要的参数,这里为null

public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver,@Nullable FailureHandler failureHandler) {Assert.notNull(factoryType, "'factoryType' must not be null");//从factories 中获取指定接口类型的所有实现//factories就是加载步骤中返回的resultList<String> implementationNames = loadFactoryNames(factoryType);logger.trace(LogMessage.format("Loaded [%s] names: %s", factoryType.getName(), implementationNames));List<T> result = new ArrayList<>(implementationNames.size());//定义失败处理器FailureHandler failureHandlerToUse = (failureHandler != null) ? failureHandler : THROWING_FAILURE_HANDLER;//循环,实例化for (String implementationName : implementationNames) {//通过构造函数实例化T factory = instantiateFactory(implementationName, factoryType, argumentResolver, failureHandlerToUse);if (factory != null) {result.add(factory);}}//根据order 排序AnnotationAwareOrderComparator.sort(result);return result;
}

最终返回排序后的ApplicationContextInitializer 实例,赋值SpringApplication 的 initializers 变量。

执行

执行会在SpringApplication类的prepareContext(准备上下文)中进行调用,如图所示:
在这里插入图片描述

	//返回一个只读的有序,LinkedHashSet 类型public Set<ApplicationContextInitializer<?>> getInitializers() {return asUnmodifiableOrderedSet(this.initializers);}
	protected void applyInitializers(ConfigurableApplicationContext context) {//获取所有的ApplicationContextInitializer实例for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);// 判断ApplicationContextInitializer实例泛型是否与context对象类型一致Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");// 调用ApplicationContextInitializer实例的initialize方法进行初始化操作initializer.initialize(context);}}

实例2加载原理

创建一个实现ApplicationContextInitializer接口的类,在SpringApplication 中使用addInitializers添加,如MyInitializer2

我们使用addInitializers 将ApplicationContextInitializer接口的实现加入到SpringApplication中。

	public void addInitializers(ApplicationContextInitializer<?>... initializers) {this.initializers.addAll(Arrays.asList(initializers));}

initializers 就是 SpringApplication中的initializers变量,执行点同实例1,在准备上下文的时候执行,由于执行前会进行一次排序,所以他们两的顺序是正确的。

实例3加载原理

创建一个实现ApplicationContextInitializer接口的类,在application.ymlapplication.properties中使用context.initializer.classes添加,如MyInitializer3

该处通过配置文件添加ApplicationContextInitializer实现类,并且通过DelegatingApplicationContextInitializer 初始化器进行加载和执行。

在这里插入图片描述
DelegatingApplicationContextInitializer 被定义在了spring-boot.jar 的 META-INF/spring.factories中,并且由于他的order是0,所以会在我们自定义MyInitializer和MyInitializer2 前执行,它是另外一种独立的初始化器,专门用于将配置文件中的ApplicationContextInitializer实现类加载到Spring容器中。

在这里插入图片描述
执行在DelegatingApplicationContextInitializer类的applyInitializers方法中

private void applyInitializers(ConfigurableApplicationContext context,List<ApplicationContextInitializer<?>> initializers) {//排序initializers.sort(new AnnotationAwareOrderComparator());for (ApplicationContextInitializer initializer : initializers) {//调用initialize方法initializer.initialize(context);}
}

实例4加载原理

创建一个实现EnvironmentPostProcessor接口的类,在spring.factories中添加,如MyEnvironmentPostProcessor
实例4是在所有的测试中最先打印日志的,是因为它是在prepareEnvironment(准备环境)中执行,而前面3个实例都是在prepareContext(准备上下文)中执行。
该实例中EventPublishingRunListener会调用prepareEnvironment方法,EventPublishingRunListener被定义在Spring Boot Jar包的META-INF/spring.factories中,用于发布各种SpringApplicationEvent事件。

EventPublishingRunListener类中

public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,ConfigurableEnvironment environment) {//广播环境准备完成事件multicastInitialEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}private void multicastInitialEvent(ApplicationEvent event) {//刷新SimpleApplicationEventMulticaster中的事件列表refreshApplicationListeners();//广播事件this.initialMulticaster.multicastEvent(event);
}private void refreshApplicationListeners() {this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);
}

SimpleApplicationEventMulticaster类中

public void multicastEvent(ApplicationEvent event) {multicastEvent(event, null);
}@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));// 获取执行事件的线程池Executor executor = getTaskExecutor();//获取指定事件类型的事件集合for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {//如果定义了执行线程池,则用线程池调用if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {//同步调用监听器invokeListener(listener, event);}}
}protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
//获取失败处理器ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {doInvokeListener(listener, event);}
}@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {//此处执行事件监听器的onApplicationEvent方法listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg = ex.getMessage();if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||(event instanceof PayloadApplicationEvent payloadEvent &&matchesClassCastMessage(msg, payloadEvent.getPayload().getClass()))) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// -> let's suppress the exception.Log loggerToUse = this.lazyLogger;if (loggerToUse == null) {loggerToUse = LogFactory.getLog(getClass());this.lazyLogger = loggerToUse;}if (loggerToUse.isTraceEnabled()) {loggerToUse.trace("Non-matching event type for listener: " + listener, ex);}}else {throw ex;}}
}

listener.onApplicationEvent(event);处,在本例中为EnvironmentPostProcessorApplicationListener

EnvironmentPostProcessorApplicationListener类中:

public void onApplicationEvent(ApplicationEvent event) {
//根据各个事件类型分别去处理if (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {onApplicationEnvironmentPreparedEvent(environmentPreparedEvent);}if (event instanceof ApplicationPreparedEvent) {onApplicationPreparedEvent();}if (event instanceof ApplicationFailedEvent) {onApplicationFailedEvent();}
}private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {ConfigurableEnvironment environment = event.getEnvironment();SpringApplication application = event.getSpringApplication();// 获取所有的 EnvironmentPostProcessor,然后执行其 postProcessEnvironment 方法for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),event.getBootstrapContext())) {postProcessor.postProcessEnvironment(environment, application);}
}// 获取所有的 EnvironmentPostProcessor
List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ResourceLoader resourceLoader,ConfigurableBootstrapContext bootstrapContext) {ClassLoader classLoader = (resourceLoader != null) ? resourceLoader.getClassLoader() : null;//postProcessorsFactory 是一个函数表达式EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);return postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext);
}

EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);中的postProcessorsFactory是在EnvironmentPostProcessorApplicationListener实例化的时候初始化,根据前面的文章我们知道EnvironmentPostProcessorApplicationListener是一个监听器,会在SpringBoot初始化的时候初始化。

public EnvironmentPostProcessorApplicationListener() {this(EnvironmentPostProcessorsFactory::fromSpringFactories);
}private EnvironmentPostProcessorApplicationListener(Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory) {this.postProcessorsFactory = postProcessorsFactory;this.deferredLogs = new DeferredLogs();
}static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {return new SpringFactoriesEnvironmentPostProcessorsFactory(SpringFactoriesLoader.forDefaultResourceLocation(classLoader));
}

EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) 会在EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader); apply的时候调用,如果没有加载META-INF/spring.factories会再这里再次加载。

EnvironmentPostProcessorsFactory 的主要作用是实例化EnvironmentPostProcessorSpringFactoriesEnvironmentPostProcessorsFactory是其子类。

SpringFactoriesEnvironmentPostProcessorsFactory类中:

public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,ConfigurableBootstrapContext bootstrapContext) {ArgumentResolver argumentResolver = ArgumentResolver.of(DeferredLogFactory.class, logFactory);//向argumentResolver对象中添加ConfigurableBootstrapContext.class和bootstrapContext,获取更新后的argumentResolver对象argumentResolver = argumentResolver.and(ConfigurableBootstrapContext.class, bootstrapContext);// // 向argumentResolver对象中添加BootstrapRegistry.class和bootstrapContext,获取更新后的argumentResolver对象argumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext); 通过this.loader.load方法加载EnvironmentPostProcessor类型的对象,参数为argumentResolverargumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext);//加载EnvironmentPostProcessor类型的对象return this.loader.load(EnvironmentPostProcessor.class, argumentResolver);
}

最后循环调用postProcessor.postProcessEnvironment(environment, application);完成执行。

总结

同样的,用一张图来总结本文整个流程:
在这里插入图片描述


作者其他文章:
Prometheus 系列文章

  1. Prometheus 的介绍和安装
  2. 直观感受PromQL及其数据类型
  3. PromQL之选择器和运算符
  4. PromQL之函数
  5. Prometheus 告警机制介绍及命令解读
  6. Prometheus 告警模块配置深度解析
  7. Prometheus 配置身份认证
  8. Prometheus 动态拉取监控服务
  9. Prometheus 监控云Mysql和自建Mysql

Grafana 系列文章,版本:OOS v9.3.1

  1. Grafana 的介绍和安装
  2. Grafana监控大屏配置参数介绍(一)
  3. Grafana监控大屏配置参数介绍(二)
  4. Grafana监控大屏可视化图表
  5. Grafana 查询数据和转换数据
  6. Grafana 告警模块介绍
  7. Grafana 告警接入飞书通知

Spring Boot Admin 系列

  1. Spring Boot Admin 参考指南
  2. SpringBoot Admin服务离线、不显示健康信息的问题
  3. Spring Boot Admin2 @EnableAdminServer的加载
  4. Spring Boot Admin2 AdminServerAutoConfiguration详解
  5. Spring Boot Admin2 实例状态监控详解
  6. Spring Boot Admin2 自定义JVM监控通知
  7. Spring Boot Admin2 自定义异常监控
  8. Spring Boot Admin 监控指标接入Grafana可视化

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

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

相关文章

网络故障管理

网络故障管理是以最快的方式查找、隔离和排除网络故障的过程。故障管理是网络管理的重要组成部分&#xff0c;它通过快速解决故障来最大限度地减少停机时间并防止设备故障&#xff0c;从而确保最佳的网络可用性并防止业务损失。 网络故障监控是故障管理的第一步&#xff0c;因…

NLP+VS︱深度学习数据集标注工具、图像语料数据库、实验室搜索ing....

from: https://blog.csdn.net/sinat_26917383/article/details/54908389 一、NLP标注工具 来源&#xff1a;《构想&#xff1a;中文文本标注工具&#xff08;附开源文本标注工具列表&#xff09;》 Chinese-Annotator 来源&#xff1a;https://github.com/crownpku/Chinese-…

wince集锦

为什么80%的码农都做不了架构师&#xff1f;>>> WinCE驱动开发问题精华集锦在mediaplayer全屏播放的时候&#xff0c;我可以用键盘上的某一个键调节声音大小&#xff0c;现在我想在屏幕上显示调节的结果就跟我们看电视一样能出来一些标记。当声音变大在屏幕上就增多…

k8s技术预研8--深入掌握Kubernetes Service

本文内容已经基于k8s v1.8.8进行了验证测试。 k8s的Service定义了一个服务的访问入口地址&#xff0c;前端的应用通过这个入口地址访问其背后的一组由Pod副本组成的集群实例&#xff0c;来自外部的访问请求被负载均衡到后端的各个容器应用上。Service与其后端Pod副本集群之间则…

spring boot 与 iview 前后端分离架构之开发环境基于docker的部署的实现(三十六)

spring boot 与 iview 前后端分离架构之开发环境基于docker的后端的部署的实现&#xff08;三十六&#xff09; 公众号基于docker的后端的部署安装mysql数据库创建数据库 安装redis安装docker创建基础镜像编写后台管理系统的DockerFile文件pom.xml的配置新增application-prod.y…

回归模型评价指标R2_score

搞清楚R2_score计算之前&#xff0c;我们还需要了解几个统计学概念。 若用 y i y_i yi​表示真实的观测值&#xff0c;用 y ˉ \bar{y} yˉ​表示真实观测值的平均值&#xff0c;用 y i ^ \hat{y_i} yi​^​表示预测值,则&#xff1a; 回归平方和&#xff1a;SSR 即估计值与…

Python网络编程

查看Python中支持的编码方式&#xff1a;https://docs.python.org/3/library/codecs.html?highlightutf IP地址工具&#xff1a;http://ipblock.chacuo.net/ 查看应用程序进程PID&#xff1a; 1.启动任务管理器&#xff0c;点击进程&#xff1a;默认是这样的&#xff1a; 2…

Redis的安装等相关问题

1.1 下载 从官网下载&#xff0c;Redis官网点击下载 或者直接下载整合下好的&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Vj9jNq2mh5lZLVFSVo5cFw&shflsharepset 提取码&#xff1a;m599 通过SecureCRT将下载的文件上传到/opt/work目录 如果上传rz不能使用…

路由器 ------ 动态路由 (1) ---- RIP

RIP &#xff1a; 根据Bellman-Ford算法计算路由 距离矢量型协议&#xff08;DV&#xff09;---- 路由器之间传递路由条目 &#xff1b;距离就是开销值&#xff0c;矢量就是下一跳 邻居关系 ---- 相邻的两个路由器&#xff0c;链接在共同的广播域内&#xff0c;通过广播的形…

华为云HCS解决方案笔记HUAWEI CLOUD Stack【面试篇】

目录 HCS方案 一、定义 1、特点 2、优点 二、云服务 1、云管理 2、存储服务 3、网络服务 4、计算服务 5、安全服务 6、灾备服务 7、容器服务 三、应用场景 四、HCS功能层 五、OpenStack网络平面规划 六、ManageOne运维面 1、首页 2、集中监控 3、资源拓扑 …

关于Arthas如何远程监视Java程序

在使用 Arthas 之前&#xff0c;当遇到 Java 线上问题时&#xff0c;如 CPU 飙升、负载突高、内存溢出等问题&#xff0c;你需要查命令&#xff0c;查网络&#xff0c;然后 jps、jstack、jmap、jhat、jstat、hprof 等一通操作。最终焦头烂额&#xff0c;还不一定能查出问题所在…

NLP+VS︱深度学习数据集标注工具、图像语料数据库、实验室搜索ing...

~~因为不太会使用opencv、matlab工具&#xff0c;所以在找一些比较简单的工具。 . 一、NLP标注工具 来源&#xff1a;《构想&#xff1a;中文文本标注工具&#xff08;附开源文本标注工具列表&#xff09;》 Chinese-Annotator 来源&#xff1a;https://github.com/crownpku/…

kube-proxy源码阅读(iptables实现)

Reference 文章目录 1 入口2 ProxyServer创建及调用3 ProxyServer 核心调用流程3.1 func (o *Options) Run() err3.2 func (o *Options) runLoop() error3.3 func (s *ProxyServer) Run() error3.4 func (proxier *Proxier) SyncLoop() 4 资源事件处理流程4.1 Service事件4.2 …

windows_删除多余网络适配器(删除/卸载多余网卡)/删除TAP虚拟网卡NIC

文章目录 Device Manager检查所有NIC状态利用资源监视器查看网卡情况接入不同网络对于计算机网络环境造成不同的影响接入传统的wifi接入手机热点的wifi Device Manager 删除指定的Network adapter(网卡又称为网络适配器)完成之后你可能需要重启才可以上网 检查所有NIC状态 包…

值得一阅的Kali系统的使用小技巧

目录 写在最前1.软件安装软件源关于AMD显卡驱动浏览器中文输入法下载工具代理软件QQSteam 2.使用优化ssh服务开启Grub修改Zsh和PowerShell命令标头修改VSCode内置终端字体间距过大问题 Aria2配置文件 写在最前 不定期更新 1.软件安装 软件源 推荐使用中科大源&#xff0c;官…

基于geoserver开发地图发布服务

写在前面&#xff1a;我在github上创建了对应的项目&#xff0c;可点此跳转&#xff0c;本文的所有源码均可在项目里找到&#xff0c;欢迎大家访问交流 一、开发背景 在gis领域&#xff0c;geoserver是后端地图发布的开源项目。目前我们在启动服务后&#xff0c;可通过自带的…

CIPSTAT

AT_TCPIP_CmdFunc_CIPSTART //start up tcpip connection 1&#xff09;if (gCipBearer ! BEARER_WIFI) 承载是GPRS(1)还是WIFI&#xff08;2&#xff09;&#xff0c;若非WIFI&#xff0c;获取SimStatus 2)if ((!cipMux_multiIp && (CIP_INITIALg_uCipContexts.nBeare…

Cloud Computing:云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系

Cloud Computing&#xff1a;云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系 目录 云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系 从陈坤/辛芷蕾主演电…

relation-graph关系图谱组件2.0版本遇到的问题

前提&#xff1a;之前已经写过一篇1.1版本的问题&#xff0c;这里就不过多讲了&#xff08;如果想要解决火狐低版本兼容&#xff0c;看那个就行&#xff09; 这次主要讲的是和1.X版本的区别和一些其它问题 区别 参数名不同&#xff1a;以前的links>lines (虽然现在links也…

高压放大器在微流控技术的应用研究

随着微流控技术的不断发展&#xff0c;其在生物医学、环境监测、化学分析等领域中的应用越来越广泛&#xff0c;也对相关器件的性能提出了更高的要求。其中&#xff0c;高压放大器作为一种电子元器件&#xff0c;在微流控技术中具有重要的作用。下面安泰电子将从高压放大器在微…