Nacos源码详解

因为Eureka的闭源,Nacos成为了现在Spring Cloud微服务注册中心的主流方案,那咱们废话不多说,直接开始读源码(基于2.2.0版本)。

首先我们知道Nacos是基于Springboot实现自动注入的,老规矩我们来到spring-cloud-alibaba-nacos-discovery包下面的META-INF\spring.factories配置文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration

我们首先来到NacosDiscoveryAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic NacosDiscoveryProperties nacosProperties() {return new NacosDiscoveryProperties();}@Bean@ConditionalOnMissingBeanpublic NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties) {return new NacosServiceDiscovery(discoveryProperties);}}

这个自动配置类注入了两个Bean,第一个Bean是从配置文件中读spring.cloud.nacos.discovery前缀的配置项,然后是第二个Bean

public class NacosServiceDiscovery {private NacosDiscoveryProperties discoveryProperties;public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties) {this.discoveryProperties = discoveryProperties;}/*** Return all instances for the given service.* @param serviceId id of service* @return list of instances* @throws NacosException nacosException*/public List<ServiceInstance> getInstances(String serviceId) throws NacosException {String group = discoveryProperties.getGroup();List<Instance> instances = discoveryProperties.namingServiceInstance().selectInstances(serviceId, group, true);return hostToServiceInstanceList(instances, serviceId);}/*** Return the names of all services.* @return list of service names* @throws NacosException nacosException*/public List<String> getServices() throws NacosException {String group = discoveryProperties.getGroup();ListView<String> services = discoveryProperties.namingServiceInstance().getServicesOfServer(1, Integer.MAX_VALUE, group);return services.getData();}public static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) {List<ServiceInstance> result = new ArrayList<>(instances.size());for (Instance instance : instances) {ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId);if (serviceInstance != null) {result.add(serviceInstance);}}return result;}public static ServiceInstance hostToServiceInstance(Instance instance,String serviceId) {if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {return null;}NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();nacosServiceInstance.setHost(instance.getIp());nacosServiceInstance.setPort(instance.getPort());nacosServiceInstance.setServiceId(serviceId);Map<String, String> metadata = new HashMap<>();metadata.put("nacos.instanceId", instance.getInstanceId());metadata.put("nacos.weight", instance.getWeight() + "");metadata.put("nacos.healthy", instance.isHealthy() + "");metadata.put("nacos.cluster", instance.getClusterName() + "");metadata.putAll(instance.getMetadata());nacosServiceInstance.setMetadata(metadata);if (metadata.containsKey("secure")) {boolean secure = Boolean.parseBoolean(metadata.get("secure"));nacosServiceInstance.setSecure(secure);}return nacosServiceInstance;}

根据代码和注释可以看出,这个Bean的核心功能是根据配置文件里Nacos的相关配置,获取实例和实例对象转化的一些功能,然后是NacosDiscoveryEndpointAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Endpoint.class)
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryEndpointAutoConfiguration {@Bean@ConditionalOnMissingBean@ConditionalOnEnabledEndpointpublic NacosDiscoveryEndpoint nacosDiscoveryEndpoint(NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosDiscoveryEndpoint(nacosDiscoveryProperties);}@Bean@ConditionalOnEnabledHealthIndicator("nacos-discovery")public HealthIndicator nacosDiscoveryHealthIndicator(NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosDiscoveryHealthIndicator(nacosDiscoveryProperties.namingServiceInstance());}}

这个类注入了两个Bean,第一个Bean NacosDiscoveryEndpoint 的作用是作为Nacos服务发现的端点,获取当前客户端的所有注册的服务。

第二个Bean NacosDiscoveryHealthIndicator的作用是通过向Nacos注册中心请求/operator/metrics 接口来确认健康状态。

接下来这个自动配置类NacosServiceRegistryAutoConfiguration比较核心

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
/*是否开启Nacos服务发现*/
@ConditionalOnNacosDiscoveryEnabled
/*是否开启自动注册,默认为True*/
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",matchIfMissing = true)
/*在以下几个配置类装配完成后才进行装配*/
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,AutoServiceRegistrationAutoConfiguration.class,NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {/*读取配置文件*/@Beanpublic NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosServiceRegistry(nacosDiscoveryProperties);}/*Nacos服务注册Bean*/@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,ApplicationContext context) {return new NacosRegistration(nacosDiscoveryProperties, context);}/*Nacos服务自动注册Bean*/@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,NacosRegistration registration) {return new NacosAutoServiceRegistration(registry,autoServiceRegistrationProperties, registration);}}

该配置类装配了三个Bean,我们重点关注下第三个同来实现服务自动注册的Bean NacosAutoServiceRegistration

public class NacosAutoServiceRegistrationextends AbstractAutoServiceRegistration<Registration> {private static final Logger log = LoggerFactory.getLogger(NacosAutoServiceRegistration.class);private NacosRegistration registration;public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,NacosRegistration registration) {super(serviceRegistry, autoServiceRegistrationProperties);this.registration = registration;}@Deprecatedpublic void setPort(int port) {getPort().set(port);}@Overrideprotected NacosRegistration getRegistration() {if (this.registration.getPort() < 0 && this.getPort().get() > 0) {this.registration.setPort(this.getPort().get());}Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");return this.registration;}@Overrideprotected NacosRegistration getManagementRegistration() {return null;}@Overrideprotected void register() {if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {log.debug("Registration disabled.");return;}if (this.registration.getPort() < 0) {this.registration.setPort(getPort().get());}super.register();}@Overrideprotected void registerManagement() {if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {return;}super.registerManagement();}@Overrideprotected Object getConfiguration() {return this.registration.getNacosDiscoveryProperties();}@Overrideprotected boolean isEnabled() {return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();}@Override@SuppressWarnings("deprecation")protected String getAppName() {String appName = registration.getNacosDiscoveryProperties().getService();return StringUtils.isEmpty(appName) ? super.getAppName() : appName;}

通过名字我们可以看出,这个Bean的核心是redister方法,该方法调用的是父抽象类AbstractAutoServiceRegistration中的实现,然后在父类中它又调用了接口ServiceRegistry的register方法,实际由NacosServiceRegistry实现,我们进入到NacosServiceRegistry实现的register方法

	public void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");return;}String serviceId = registration.getServiceId();String group = nacosDiscoveryProperties.getGroup();Instance instance = getNacosInstanceFromRegistration(registration);try {namingService.registerInstance(serviceId, group, instance);log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,instance.getIp(), instance.getPort());}catch (Exception e) {log.error("nacos registry, {} register failed...{},", serviceId,registration.toString(), e);// rethrow a RuntimeException if the registration is failed.// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132rethrowRuntimeException(e);}}

然后我们重点关注其中namingService.registerInstance方法,namingService是一个接口,由NacosNamingService实现,我们进入到方法实现

    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {//首先判断该实例是临时还是持久的,默认是临时的if (instance.isEphemeral()) {//新建心跳对象BeatInfo beatInfo = new BeatInfo();//设置serviceNamebeatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));//设置IPbeatInfo.setIp(instance.getIp());//设置端口号beatInfo.setPort(instance.getPort());//设置集群名beatInfo.setCluster(instance.getClusterName());//设置实例权重beatInfo.setWeight(instance.getWeight());beatInfo.setMetadata(instance.getMetadata());beatInfo.setScheduled(false);long instanceInterval = instance.getInstanceHeartBeatInterval();//设置发送心跳时间间隔,默认5秒beatInfo.setPeriod(instanceInterval == 0 ? DEFAULT_HEART_BEAT_INTERVAL : instanceInterval);//放入定时线程池等待执行beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);}//进行服务注册serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);}

该方法首先封装了一个心跳对象,并放入ScheduledThreadPoolExecutor线程池中,默认每5秒执行一次,然后调用注册中心代理serverProxy通过向注册中心/instance接口发送进行服务注册

    public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}",namespaceId, serviceName, instance);final Map<String, String> params = new HashMap<String, String>(9);params.put(CommonParams.NAMESPACE_ID, namespaceId);params.put(CommonParams.SERVICE_NAME, serviceName);params.put(CommonParams.GROUP_NAME, groupName);params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());params.put("ip", instance.getIp());params.put("port", String.valueOf(instance.getPort()));params.put("weight", String.valueOf(instance.getWeight()));params.put("enable", String.valueOf(instance.isEnabled()));params.put("healthy", String.valueOf(instance.isHealthy()));params.put("ephemeral", String.valueOf(instance.isEphemeral()));params.put("metadata", JSON.toJSONString(instance.getMetadata()));reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);}

我们来到注册中心的/instance接口,重点关注InstanceController的register方法

    @CanDistro@PostMapping@TpsControl(pointName = "NamingInstanceRegister", name = "HttpNamingInstanceRegister")@Secured(action = ActionTypes.WRITE)public String register(HttpServletRequest request) throws Exception {final String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,Constants.DEFAULT_NAMESPACE_ID);final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);NamingUtils.checkServiceNameFormat(serviceName);final Instance instance = HttpRequestInstanceBuilder.newBuilder().setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();getInstanceOperator().registerInstance(namespaceId, serviceName, instance);NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(), "", false, namespaceId,NamingUtils.getGroupName(serviceName), NamingUtils.getServiceName(serviceName), instance.getIp(),instance.getPort()));return "ok";}

重点关注getInstanceOperator().registerInstance(namespaceId, serviceName, instance)方法

    /*** This method creates {@code IpPortBasedClient} if it doesn't exist.*/@Overridepublic void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);//判断是否临时boolean ephemeral = instance.isEphemeral();//获取客户端IDString clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);//如果客户端不存在则新建createIpPortClientIfAbsent(clientId);//封装service对象Service service = getService(namespaceId, serviceName, ephemeral);//进行实例注册clientOperationService.registerInstance(service, instance, clientId);}

clientOperationService为一个接口且有多个实现,我们查看其实现类找到EphemeralClientOperationServiceImpl中的registerInstance方法

    public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {//检查实例是否合法NamingUtils.checkInstanceIsLegal(instance);//获取单例的serviceService singleton = ServiceManager.getInstance().getSingleton(service);if (!singleton.isEphemeral()) {throw new NacosRuntimeException(NacosException.INVALID_PARAM,String.format("Current service %s is persistent service, can't register ephemeral instance.",singleton.getGroupedServiceName()));}//获取客户端Client client = clientManager.getClient(clientId);if (!clientIsLegal(client, clientId)) {return;}//封装实例发布信息InstancePublishInfo instanceInfo = getPublishInfo(instance);client.addServiceInstance(singleton, instanceInfo);client.setLastUpdatedTime();client.recalculateRevision();//通知中心发布客户端服务注册事件NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));}

然后我们关注publishEvent

    /*** Request publisher publish event Publishers load lazily, calling publisher.** @param eventType class Instances type of the event type.* @param event     event instance.*/private static boolean publishEvent(final Class<? extends Event> eventType, final Event event) {if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {return INSTANCE.sharePublisher.publish(event);}final String topic = ClassUtils.getCanonicalName(eventType);EventPublisher publisher = INSTANCE.publisherMap.get(topic);if (publisher != null) {return publisher.publish(event);}if (event.isPluginEvent()) {return true;}LOGGER.warn("There are no [{}] publishers for this event, please register", topic);return false;}

在DefaultPublisher中的publish方法,加入阻塞队列等待执行

    @Overridepublic boolean publish(Event event) {checkIsStart();//加入阻塞队列尾部boolean success = this.queue.offer(event);if (!success) {LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);//接收事件receiveEvent(event);return true;}return true;}void checkIsStart() {if (!initialized) {throw new IllegalStateException("Publisher does not start");}}@Overridepublic void shutdown() {this.shutdown = true;this.queue.clear();}public boolean isInitialized() {return initialized;}/*** Receive and notifySubscriber to process the event.** @param event {@link Event}.*/void receiveEvent(Event event) {final long currentEventSequence = event.sequence();//检查有无订阅者if (!hasSubscriber()) {LOGGER.warn("[NotifyCenter] the {} is lost, because there is no subscriber.", event);return;}// Notification single event listenerfor (Subscriber subscriber : subscribers) {if (!subscriber.scopeMatches(event)) {continue;}// Whether to ignore expiration eventsif (subscriber.ignoreExpireEvent() && lastEventSequence > currentEventSequence) {LOGGER.debug("[NotifyCenter] the {} is unacceptable to this subscriber, because had expire",event.getClass());continue;}// Because unifying smartSubscriber and subscriber, so here need to think of compatibility.// Remove original judge part of codes.//通知订阅者notifySubscriber(subscriber, event);}}@Overridepublic void notifySubscriber(final Subscriber subscriber, final Event event) {LOGGER.debug("[NotifyCenter] the {} will received by {}", event, subscriber);final Runnable job = () -> subscriber.onEvent(event);final Executor executor = subscriber.executor();if (executor != null) {executor.execute(job);} else {try {//执行事件job.run();} catch (Throwable e) {LOGGER.error("Event callback exception: ", e);}}}

然后我们通过ClientRegisterServiceEvent的其他引用找到了ClientServiceIndexesManager中的onEvent方法,发现ClientRegisterServiceEvent事件被封装成了ServiceChangedEvent并发布

    @Overridepublic void onEvent(Event event) {if (event instanceof ClientOperationEvent.ClientReleaseEvent) {handleClientDisconnect((ClientOperationEvent.ClientReleaseEvent) event);} else if (event instanceof ClientOperationEvent) {handleClientOperation((ClientOperationEvent) event);}}private void handleClientDisconnect(ClientOperationEvent.ClientReleaseEvent event) {Client client = event.getClient();for (Service each : client.getAllSubscribeService()) {removeSubscriberIndexes(each, client.getClientId());}DeregisterInstanceReason reason = event.isNative()? DeregisterInstanceReason.NATIVE_DISCONNECTED : DeregisterInstanceReason.SYNCED_DISCONNECTED;long currentTimeMillis = System.currentTimeMillis();for (Service each : client.getAllPublishedService()) {removePublisherIndexes(each, client.getClientId());InstancePublishInfo instance = client.getInstancePublishInfo(each);NotifyCenter.publishEvent(new DeregisterInstanceTraceEvent(currentTimeMillis,"", false, reason, each.getNamespace(), each.getGroup(), each.getName(),instance.getIp(), instance.getPort()));}}private void handleClientOperation(ClientOperationEvent event) {Service service = event.getService();String clientId = event.getClientId();if (event instanceof ClientOperationEvent.ClientRegisterServiceEvent) {addPublisherIndexes(service, clientId);} else if (event instanceof ClientOperationEvent.ClientDeregisterServiceEvent) {removePublisherIndexes(service, clientId);} else if (event instanceof ClientOperationEvent.ClientSubscribeServiceEvent) {addSubscriberIndexes(service, clientId);} else if (event instanceof ClientOperationEvent.ClientUnsubscribeServiceEvent) {removeSubscriberIndexes(service, clientId);}}private void addPublisherIndexes(Service service, String clientId) {publisherIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>());publisherIndexes.get(service).add(clientId);NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true));}

而Nacos注册中心是通过JRaftServer的NacosStateMachine中RequestProcessor对象去执行onApply方法,而RequestProcessor为抽象类,其实现类为InstanceMetadataProcessor,我们来到其中的onApply方法

    @Overridepublic Response onApply(WriteRequest request) {readLock.lock();try {MetadataOperation<InstanceMetadata> op = serializer.deserialize(request.getData().toByteArray(), processType);switch (DataOperation.valueOf(request.getOperation())) {case ADD:case CHANGE:updateInstanceMetadata(op);break;case DELETE:deleteInstanceMetadata(op);break;default:return Response.newBuilder().setSuccess(false).setErrMsg("Unsupported operation " + request.getOperation()).build();}return Response.newBuilder().setSuccess(true).build();} catch (Exception e) {Loggers.RAFT.error("onApply {} instance metadata operation failed. ", request.getOperation(), e);String errorMessage = null == e.getMessage() ? e.getClass().getName() : e.getMessage();return Response.newBuilder().setSuccess(false).setErrMsg(errorMessage).build();} finally {readLock.unlock();}}private void updateInstanceMetadata(MetadataOperation<InstanceMetadata> op) {Service service = Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName());service = ServiceManager.getInstance().getSingleton(service);namingMetadataManager.updateInstanceMetadata(service, op.getTag(), op.getMetadata());NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true));}private void deleteInstanceMetadata(MetadataOperation<InstanceMetadata> op) {Service service = Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName());service = ServiceManager.getInstance().getSingleton(service);namingMetadataManager.removeInstanceMetadata(service, op.getTag());}

核心在NamingMetadataManager的updateInstanceMetadata中

      private ConcurrentMap<Service, ConcurrentMap<String, InstanceMetadata>> instanceMetadataMap;/*** Update instance metadata.** @param service          service* @param metadataId       instance metadata id* @param instanceMetadata new instance metadata*/public void updateInstanceMetadata(Service service, String metadataId, InstanceMetadata instanceMetadata) {if (!instanceMetadataMap.containsKey(service)) {instanceMetadataMap.putIfAbsent(service, new ConcurrentHashMap<>(INITIAL_CAPACITY));}instanceMetadataMap.get(service).put(metadataId, instanceMetadata);}

其存放客户端实例的对象是一个两层的ConcurrentHashMap,第一层的Map key为service对象,第二层的Map Key为具体的实例Id,value为实例对象。

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

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

相关文章

浅谈SpringMVC的请求流程

目录标题 浅谈SpringMVC的请求流程SpringMVC的介绍SpringMVC的逻辑概念运行图解知识总结 浅谈SpringMVC的请求流程 对于SpringMVC而言重点是了解它的底层运行逻辑&#xff0c;从而可以根据其逻辑来进行实际业务的操作或者是利用原理增强业务的功能性&#xff0c;最终达到项目预…

利用hutool工具类实现验证码功能

hutool工具类实现验证码 一.生成验证码二.校验验证码三.使用案例1.引入hutool工具类2.VerifyCodeResp接口响应体3.VerifyCodeController验证码工具类4.测试验证5.项目结构及源码下载 利用hutool工具类&#xff0c;可以很方便生成不同类型的验证码。这里简单记录下使用过程。 一…

基于OSATE环境的AADL项目——简单的项目构建与分析示例

一、背景 本文描述了一个非常简单的AADL项目的构建&#xff0c;以及一个示例项目的分析过程。本文主要记录了OSATE工具环境的一些基本操作&#xff0c;适用于刚刚了解OSATE之后&#xff0c;对于整个工具环境无从下手的小白。 因为基于OSATE环境的AADL项目的构建和分析的详细示…

LeetCode算法心得——美丽塔 I(HashMap)

大家好&#xff0c;我是晴天学长&#xff0c;hashmap的灵活应用&#xff0c;然后边界的细节处理&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。 1) .美丽塔 美丽塔 I 给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。 你的任务是在坐标轴…

Keil 无法烧写程序

问题描述&#xff1a; Keil MDK V5.38 按 F8 键无法烧录程序&#xff0c;提示: Error: Flash Download failed - "Cortex-M7", No Algorithm found for: 08000000H - 080013D3H 解决办法&#xff1a; Debug 工具改为&#xff1a;ST-Link Debugger Debug 的 Conne…

【C++】STL之list深度剖析及模拟实现

目录 前言 一、list 的使用 1、构造函数 2、迭代器 3、增删查改 4、其他函数使用 二、list 的模拟实现 1、节点的创建 2、push_back 和 push_front 3、普通迭代器 4、const 迭代器 5、增删查改(insert、erase、pop_back、pop_front) 6、构造函数和析构函数 6.1、默认构造…

Qt QCustomPlot介绍

介绍 主要介绍qcustomplot及其用法 最新版本:QCustomPlot Patch Release 2.1.1//November 6, 2022 下载:https://www.qcustomplot.com/index.php/download 官网:https://www.qcustomplot.com/index.php 简单使用 mainwindow.h /**************************************…

【pytest】 参数化@pytest.mark.parametrize

1.创建 test_parametrize.py 通过 pytest.mark.parametrize 方法设置参数 import pytestimport math#pytest参数化 pytest.mark.parametrize("base,exponent,expected", # 参数变量名称# 每个元组都是一条测试用例测试数据[(2,2,4),(3,3,9),(1,9,1),(0,9,0)],i…

R语言风险价值:ARIMA,GARCH,Delta-normal法滚动估计VaR(Value at Risk)和回测分析股票数据...

全文链接&#xff1a;http://tecdat.cn/?p24492 此分析的目的是构建一个过程&#xff0c;以在给定时变波动性的情况下正确估计风险价值。风险价值被广泛用于衡量金融机构的市场风险。我们的时间序列数据包括 1258 天的股票收益&#xff08;点击文末“阅读原文”获取完整代码数…

Java————网络编程

一 、网络编程基础 1. 为什么需要网络编程 用户在浏览器中&#xff0c;打开在线视频网站&#xff0c; 如优酷看视频&#xff0c;实质是通过网络&#xff0c; 获取到网络上的一个视频资源。 与本地打开视频文件类似&#xff0c;只是视频文件这个资源的来源是网络。 相比本地资…

汽车电子——产品标准规范汇总和梳理(车载网络)

文章目录 前言 一、菊花链 二、K Line 三、L Line 四、RS485 五、LIN 六、CAN 七、FlexRay 八、MOST 九、Bluetooth 十、LAN 十一、移动网络 十二、实施和测试 总结 前言 见《汽车电子——产品标准规范汇总和梳理》 一、菊花链 暂无统一的正式标准。 菊花链通信&…

Linux查看系统信息

# 查看操作系统的详细信息 uname -a# 查看已安装的Linux发行版信息 cat /etc/os-release# 查看Linux Standard Base (LSB)的信息 lsb_release -a# 查看主机的信息 hostnamectl# 查看文件系统的磁盘空间使用情况 df -h# 查看系统内存的使用情况 free -h# 查看网络接口的信息 ifc…

[React] react-hooks如何使用

react-hooks思想和初衷&#xff0c;也是把组件&#xff0c;颗粒化&#xff0c;单元化&#xff0c;形成独立的渲染环境&#xff0c;减少渲染次数&#xff0c;优化性能。 文章目录 1.为什么要使用hooks2.如何使用hooks2.1 useState2.2 useEffect2.3 useLayoutEffect2.4 useRef2.5…

【网络编程】TCP Socket编程

TCP Socket编程 1. ServerSocket2. Socket3. TCP的长短连接4. Socket 通信模型5. 代码示例&#xff1a;TCP 回显服务器 流套接字&#xff1a; 使用传输层TCP协议 TCP: 即Transmission Control Protocol&#xff08;传输控制协议&#xff09;&#xff0c;传输层协议。 TCP的特点…

【计算机网络】IP协议(下)

文章目录 1. 特殊的IP地址2. IP地址的数量限制3. 私有IP地址和公网IP地址私有IP为什么不能出现在公网上&#xff1f;解决方案——NAT技术的使用 4. 路由5. IP分片问题为什么要进行切片&#xff1f;如何做的分片和组装&#xff1f;16位标识3位标志13位片偏移例子 细节问题如何区…

基于springboot地方废物回收机构管理系统springboot11

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

智慧农业农场小程序源码 智慧农场系统源码

智慧农业农场小程序源码 智慧农场系统源码 一、 智慧农场系统的组成 智慧农场系统一般包括传感器、控制器、数据采集与处理平台、应用软件等组成部分。其中, 传感器主要用于采集土壤温度、湿度、光照强度等环境参数,以及作物生长状态、水肥情况等生产信息。控制器则根据传感器…

GLTF编辑器的另一个作用

1、GLB模型介绍 GLB&#xff08;GLTF Binary&#xff09;是一种用于表示三维模型和场景的文件格式。GLTF是"GL Transmission Format"的缩写&#xff0c;是一种开放的、跨平台的标准&#xff0c;旨在在各种3D图形应用程序和引擎之间进行交换和共享。 GLB文件是GLTF文件…

PyCharm 手动下载插件

插件模块一直加载失败&#xff0c;报错信息&#xff1a; Marketplace plugins are not loaded. Check the internet connection and refresh. 尝试了以下方法&#xff0c;均告失败&#xff1a; pip 换源Manage Plugin Repositories...HTTP 代理设置...关闭三个防火墙 最后选…