spring-cloud-alibaba-dubbo-issues1805修复

news2024/11/26 21:24:46

spring-cloud-alibaba-dubbo-issues1805修复

文章目录

    • @[toc]
  • 1.官方信息
  • 2.版本代码对比
  • 3.修改尝试
  • 4.验证
  • 5.总结

这个issue就是我这前写了那两篇文章的那个issue

Dubbo重启服务提供者或先启动服务消费者后启动服务提供者,消费者有时候会出现找不到服务的问题及解决

https://mp.weixin.qq.com/s/L-ejXtV9wk-hPYAc2e3jvQ

Duboo项目集成升级问题解决

https://mp.weixin.qq.com/s/-9t0tqnVX-A2fz4SNiPFdA

1.官方信息

Spring Cloud Dubbo组件去留问题讨论 #2398

https://github.com/alibaba/spring-cloud-alibaba/issues/2398

官方issue1805

https://github.com/alibaba/spring-cloud-alibaba/issues/1805

官方issue1805提交

https://github.com/alibaba/spring-cloud-alibaba/commit/fd8a6a6f6c262cbf8d20c049c84cd445651bd969

2.版本代码对比

图片

Spring-Cloud-Start-dubbo-2.2.6-RELEASE的服务注册自动配置类如下:

图片

/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.cloud.dubbo.autoconfigure;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
import com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapStartCommandLineRunner;
import com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapWrapper;
import com.alibaba.cloud.dubbo.bootstrap.event.DubboBootstrapStartedEvent;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
import com.ecwid.consul.v1.agent.model.NewService;
import com.netflix.appinfo.InstanceInfo;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.ServiceBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;

import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
import static org.springframework.util.ObjectUtils.isEmpty;

/**
 * Dubbo Service Registration Auto-{@link Configuration}.
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
 */
@Configuration(proxyBeanMethods = false)
@Import({ DubboServiceRegistrationEventPublishingAspect.class,
		DubboBootstrapStartCommandLineRunner.class })
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
		CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME,
		"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" },
		value = { DubboMetadataAutoConfiguration.class })
public class DubboServiceRegistrationAutoConfiguration {

	/**
	 * EurekaClientAutoConfiguration.
	 */
	public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration";

	/**
	 * ConsulAutoServiceRegistrationAutoConfiguration.
	 */
	public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration";

	/**
	 * ConsulAutoRegistration.
	 */
	public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration";

	/**
	 * ZookeeperAutoServiceRegistrationAutoConfiguration.
	 */
	public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration";

	private static final Logger logger = LoggerFactory
			.getLogger(DubboServiceRegistrationAutoConfiguration.class);

	@Autowired
	private DubboServiceMetadataRepository dubboServiceMetadataRepository;

	@Bean
	@Conditional({ MissingSpringCloudRegistryConfigPropertyCondition.class })
	public RegistryConfig defaultSpringCloudRegistryConfig() {
		return new RegistryConfig(ADDRESS, PROTOCOL);
	}

	private Map<ServiceRegistry<Registration>, Set<Registration>> registrations = new ConcurrentHashMap<>();

	@EventListener(DubboBootstrapStartedEvent.class)
	public void onDubboBootstrapStarted(DubboBootstrapStartedEvent event) {
		if (!event.getSource().isReady()) {
			return;
		}
		registrations.forEach(
				(registry, registrations) -> registrations.forEach(registration -> {
					attachDubboMetadataServiceMetadata(registration);
					registry.register(registration);
				}));
	}

	@EventListener(ServiceInstancePreRegisteredEvent.class)
	public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
		Registration registration = event.getSource();
		if (!DubboBootstrap.getInstance().isReady()
				|| !DubboBootstrap.getInstance().isStarted()) {
			ServiceRegistry<Registration> registry = event.getRegistry();
			synchronized (registry) {
				registrations.putIfAbsent(registry, new HashSet<>());
				registrations.get(registry).add(registration);
			}
		}
		else {
			attachDubboMetadataServiceMetadata(registration);
		}

	}

	@EventListener(ServiceInstancePreDeregisteredEvent.class)
	public void onServiceInstancePreDeregistered(
			ServiceInstancePreDeregisteredEvent event) {
		ServiceRegistry<Registration> registry = event.getRegistry();
		registrations.remove(registry);
	}

	private void attachDubboMetadataServiceMetadata(Registration registration) {
		if (registration == null) {
			return;
		}
		synchronized (registration) {
			Map<String, String> metadata = registration.getMetadata();
			attachDubboMetadataServiceMetadata(metadata);
		}
	}

	private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
		Map<String, String> serviceMetadata = dubboServiceMetadataRepository
				.getDubboMetadataServiceMetadata();
		if (!isEmpty(serviceMetadata)) {
			metadata.putAll(serviceMetadata);
		}
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
	class EurekaConfiguration implements SmartInitializingSingleton {

		@Autowired
		private ObjectProvider<Collection<ServiceBean>> serviceBeans;

		@EventListener(DubboBootstrapStartedEvent.class)
		public void onDubboBootstrapStarted(DubboBootstrapStartedEvent event) {
			DubboBootstrapWrapper wrapper = event.getSource();
			if (!wrapper.isReady()) {
				return;
			}
			registrations.forEach(
					(registry, registrations) -> registrations.removeIf(registration -> {
						if (!(registration instanceof EurekaRegistration)) {
							return false;
						}
						EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
						InstanceInfo instanceInfo = eurekaRegistration
								.getApplicationInfoManager().getInfo();

						EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
								.getInstanceConfig();
						config.setInitialStatus(InstanceInfo.InstanceStatus.UP);

						attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
						eurekaRegistration.getApplicationInfoManager()
								.registerAppMetadata(instanceInfo.getMetadata());
						eurekaRegistration.getApplicationInfoManager()
								.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
						return true;
					}));
		}

		@EventListener(ServiceInstancePreRegisteredEvent.class)
		public void onServiceInstancePreRegistered(
				ServiceInstancePreRegisteredEvent event) {
			Registration registration = event.getSource();
			if (!(registration instanceof EurekaRegistration)) {
				return;
			}

			if (DubboBootstrap.getInstance().isReady()
					&& DubboBootstrap.getInstance().isStarted()) {
				EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
				InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager()
						.getInfo();

				EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
						.getInstanceConfig();
				config.setInitialStatus(InstanceInfo.InstanceStatus.UP);

				attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
				eurekaRegistration.getApplicationInfoManager()
						.registerAppMetadata(instanceInfo.getMetadata());
			}
			else {
				EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
				EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
						.getInstanceConfig();
				config.setInitialStatus(InstanceInfo.InstanceStatus.STARTING);
			}
		}

		/**
		 * {@link EurekaServiceRegistry} will register current {@link ServiceInstance
		 * service instance} on {@link EurekaAutoServiceRegistration#start()} execution(in
		 * {@link SmartLifecycle#start() start phase}), thus this method must
		 * {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in
		 * advance.
		 */
		@Override
		public void afterSingletonsInstantiated() {
			Collection<ServiceBean> serviceBeans = this.serviceBeans.getIfAvailable();
			if (!isEmpty(serviceBeans)) {
				serviceBeans.forEach(ServiceBean::export);
			}
		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
	@AutoConfigureOrder
	class ConsulConfiguration {

		@Autowired
		private ConsulDiscoveryProperties consulDiscoveryProperties;

		@EventListener(DubboBootstrapStartedEvent.class)
		public void attachURLsIntoMetadataBeforeReRegist(
				DubboBootstrapStartedEvent event) {
			if (!event.getSource().isReady()) {
				return;
			}
			registrations.entrySet().removeIf(entry -> {
				Set<Registration> registrations = entry.getValue();
				registrations.removeIf(registration -> {
					Class<?> registrationClass = AopUtils.getTargetClass(registration);
					String registrationClassName = registrationClass.getName();
					return !CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
							.equalsIgnoreCase(registrationClassName);
				});
				return registrations.isEmpty();
			});

			registrations.forEach(
					(registry, registrations) -> registrations.forEach(registration -> {
						ConsulRegistration consulRegistration = (ConsulRegistration) registration;
						attachURLsIntoMetadata(consulRegistration);
					}));
		}

		@EventListener(ServiceInstancePreRegisteredEvent.class)
		public void onServiceInstancePreRegistered(
				ServiceInstancePreRegisteredEvent event) {
			Registration registration = event.getSource();
			attachURLsIntoMetadata((ConsulRegistration) registration);
		}

		private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
			Map<String, String> serviceMetadata = dubboServiceMetadataRepository
					.getDubboMetadataServiceMetadata();
			if (isEmpty(serviceMetadata)) {
				return;
			}
			NewService newService = consulRegistration.getService();
			if (consulDiscoveryProperties.isTagsAsMetadata()) {
				for (Map.Entry<String, String> entry : serviceMetadata.entrySet()) {
					attAsTag(newService.getTags(), entry.getKey(), entry.getValue());
				}
			}
			else {
				newService.getMeta().putAll(serviceMetadata);
			}
		}

		private void attAsTag(List<String> tags, String key, String value) {
			Iterator<String> iter = tags.iterator();
			while (iter.hasNext()) {
				String tag = iter.next();
				String[] tmp = tag.split("=");
				if (StringUtils.pathEquals(tmp[0], key)) {
					iter.remove();
				}
			}
			tags.add(key + "=" + value);
		}

	}

}

DubboServiceRegistrationEventPublishingAspect类:

/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.cloud.dubbo.registry;

import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstanceRegisteredEvent;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

/**
 * Dubbo Service Registration Event-Publishing Aspect.
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @see ServiceInstancePreRegisteredEvent
 * @see ServiceInstanceRegisteredEvent
 * @see ServiceInstancePreDeregisteredEvent
 */
@Aspect
public class DubboServiceRegistrationEventPublishingAspect
		implements ApplicationEventPublisherAware {

	/**
	 * The pointcut expression for {@link ServiceRegistry#register(Registration)}.
	 */
	public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && target(registry) && args(registration)";

	/**
	 * The pointcut expression for {@link ServiceRegistry#deregister(Registration)}.
	 */
	public static final String DEREGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(*)) && target(registry) && args(registration)";

	private ApplicationEventPublisher applicationEventPublisher;

	@Before(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
	public void beforeRegister(ServiceRegistry registry, Registration registration) {
		applicationEventPublisher.publishEvent(
				new ServiceInstancePreRegisteredEvent(registry, registration));
	}

	@Before(value = DEREGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
	public void beforeDeregister(ServiceRegistry registry, Registration registration) {
		applicationEventPublisher.publishEvent(
				new ServiceInstancePreDeregisteredEvent(registry, registration));
	}

	@After(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
	public void afterRegister(ServiceRegistry registry, Registration registration) {
		applicationEventPublisher
				.publishEvent(new ServiceInstanceRegisteredEvent(registration));
	}

	@Override
	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}

}

spring-cloud-alibaba-2022.0.0.0

https://github.com/alibaba/spring-cloud-alibaba/tree/fd8a6a6f6c262cbf8d20c049c84cd445651bd969

Spring-Cloud-Start-dubbo-2.2.7-RELEASE的服务注册自动配置类如下:

ApplicationContextEvent是一个抽象类:在容器启动、刷新、关闭和停止的时候都会发送这个事件。

图片

/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.cloud.dubbo.autoconfigure;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
import com.ecwid.consul.v1.agent.model.NewService;
import com.netflix.appinfo.InstanceInfo;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
import static org.springframework.util.ObjectUtils.isEmpty;

/**
 * Dubbo Service Registration Auto-{@link Configuration}.
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 */
@Configuration(proxyBeanMethods = false)
@Import({ DubboServiceRegistrationEventPublishingAspect.class })
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
		CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME,
		"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" },
		value = { DubboMetadataAutoConfiguration.class })
public class DubboServiceRegistrationAutoConfiguration {

	/**
	 * EurekaClientAutoConfiguration.
	 */
	public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration";

	/**
	 * ConsulAutoServiceRegistrationAutoConfiguration.
	 */
	public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration";

	/**
	 * ConsulAutoRegistration.
	 */
	public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration";

	/**
	 * ZookeeperAutoServiceRegistrationAutoConfiguration.
	 */
	public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration";

	private static final Logger logger = LoggerFactory
			.getLogger(DubboServiceRegistrationAutoConfiguration.class);

	@Autowired
	private DubboServiceMetadataRepository dubboServiceMetadataRepository;

	@Bean
	@Conditional({ MissingSpringCloudRegistryConfigPropertyCondition.class })
	public RegistryConfig defaultSpringCloudRegistryConfig() {
		return new RegistryConfig(ADDRESS, PROTOCOL);
	}

	private Map<ServiceRegistry<Registration>, Set<Registration>> registrations = new ConcurrentHashMap<>();

    // 监听ApplicationContextEvent这个事件重新注册dubbo的服务
	@Order
	@EventListener(ApplicationContextEvent.class)
	public void attachDubboMetadataAndRegistAgain(ApplicationContextEvent event) {
		registrations.forEach(
				(registry, registrations) -> registrations.forEach(registration -> {
					attachDubboMetadataServiceMetadata(registration);
					registry.register(registration);
				}));
	}
   //dubbo的aspect切拦截nacos服务注册前会发送这个事件,监听到该事件后需要将注册到nacos的服务加入到registrations
	@EventListener(ServiceInstancePreRegisteredEvent.class)
	public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
		Registration registration = event.getSource();
		ServiceRegistry<Registration> registry = event.getRegistry();
        // 这里加了一个jvm的锁
		synchronized (registry) {
			registrations.putIfAbsent(registry, new HashSet<>());
			registrations.get(registry).add(registration);
		}
	}
    
    //dubbo的aspect切面拦截服务取消注册前会发送这个时间,监听到该事件后需要将服务注册信息从registrations中移除
	@EventListener(ServiceInstancePreDeregisteredEvent.class)
	public void onServiceInstancePreDeregistered(
			ServiceInstancePreDeregisteredEvent event) {
		ServiceRegistry<Registration> registry = event.getRegistry();
		registrations.remove(registry);
	}

	private void attachDubboMetadataServiceMetadata(Registration registration) {
		if (registration == null) {
			return;
		}
		synchronized (registration) {
			Map<String, String> metadata = registration.getMetadata();
			attachDubboMetadataServiceMetadata(metadata);
		}
	}
    //这里是dubbo服务元数据,会加入到一个map集合中,然后会走服务变更,通知服务订阅者重新拉取最新的注册的服务信息(猜测)。
	private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
		Map<String, String> serviceMetadata = dubboServiceMetadataRepository
				.getDubboMetadataServiceMetadata();
		if (!isEmpty(serviceMetadata)) {
			metadata.putAll(serviceMetadata);
		}
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
	class EurekaConfiguration implements SmartInitializingSingleton {

		@Autowired
		private ObjectProvider<Collection<ServiceBean>> serviceBeans;

		@Order(Ordered.LOWEST_PRECEDENCE - 1)
		@EventListener(ApplicationContextEvent.class)
		public void onServiceInstancePreRegistered(ApplicationContextEvent event) {
			registrations.forEach((registry, registrations)-> registrations.forEach(registration -> {
				EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
				InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
				attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
			}));
		}

		/**
		 * {@link EurekaServiceRegistry} will register current {@link ServiceInstance
		 * service instance} on {@link EurekaAutoServiceRegistration#start()} execution(in
		 * {@link SmartLifecycle#start() start phase}), thus this method must
		 * {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in
		 * advance.
		 */
		@Override
		public void afterSingletonsInstantiated() {
			Collection<ServiceBean> serviceBeans = this.serviceBeans.getIfAvailable();
			if (!isEmpty(serviceBeans)) {
				serviceBeans.forEach(ServiceBean::export);
			}
		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
	@AutoConfigureOrder
	class ConsulConfiguration {

		@Order(Ordered.LOWEST_PRECEDENCE - 1)
		@EventListener(ApplicationContextEvent.class)
		public void attachURLsIntoMetadataBeforeReRegist(ApplicationContextEvent event) {
			registrations.entrySet().removeIf(entry -> {
				Set<Registration> registrations = entry.getValue();
				registrations.removeIf(registration -> {
					Class<?> registrationClass = AopUtils.getTargetClass(registration);
					String registrationClassName = registrationClass.getName();
					return !CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
							.equalsIgnoreCase(registrationClassName);
				});
				return registrations.isEmpty();
			});

			registrations.forEach(
					(registry, registrations) -> registrations.forEach(registration -> {
						ConsulRegistration consulRegistration = (ConsulRegistration) registration;
						attachURLsIntoMetadata(consulRegistration);
					}));
		}

		private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
			NewService newService = consulRegistration.getService();
			Map<String, String> serviceMetadata = dubboServiceMetadataRepository
					.getDubboMetadataServiceMetadata();
			if (!isEmpty(serviceMetadata)) {
				List<String> tags = newService.getTags();
				for (Map.Entry<String, String> entry : serviceMetadata.entrySet()) {
					tags.add(entry.getKey() + "=" + entry.getValue());
				}
			}
		}

	}

}

说明:

图片

将2022.0.0.0的start的服务注册自动装配类扣出来,放到项目中,然后注释EurekaConfiguration和ConsulConfiguration的自动装配即可,如果要用可以把先关的包引入进来,这个版本的start和2.2.7版本的这个start相差不大,可以替换使用

图片

之前通过升级解决这个问题,估计是巧合吧Duboo项目集成升级问题解决,百思不得其解,然后我就去git的官网上看了下找到了这个issue,然后官方是在spring-cloud-alibaba-2022.0.0.0这个版本才修复有提交代码记录的,由于这个版本所需要的版本如下:

图片

我们项目中的springBoot的版本是2.3.12.RELEASE,所以都不想升级版本依赖,所以想了这个办法,直接将这个类抠出来用下就可以了。

3.修改尝试

图片

package com.alibaba.cloud.dubbo.autoconfigure;

/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
import static org.springframework.util.ObjectUtils.isEmpty;

/**
 * Dubbo Service Registration Auto-{@link Configuration}.
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 */
@Configuration(proxyBeanMethods = false)
@Import({DubboServiceRegistrationEventPublishingAspect.class})
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter(name = {EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME, "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"}, value = {DubboMetadataAutoConfiguration.class})
public class DubboServiceRegistrationAutoConfiguration {

    /**
     * EurekaClientAutoConfiguration.
     */
    public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration";

    /**
     * ConsulAutoServiceRegistrationAutoConfiguration.
     */
    public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration";

    /**
     * ConsulAutoRegistration.
     */
    public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration";

    /**
     * ZookeeperAutoServiceRegistrationAutoConfiguration.
     */
    public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration";

    private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class);

    @Autowired
    private DubboServiceMetadataRepository dubboServiceMetadataRepository;

    @Bean
    @Conditional({MissingSpringCloudRegistryConfigPropertyCondition.class})
    public RegistryConfig defaultSpringCloudRegistryConfig() {
        return new RegistryConfig(ADDRESS, PROTOCOL);
    }

    private Map<ServiceRegistry<Registration>, Set<Registration>> registrations = new ConcurrentHashMap<>();

    @Order
    @EventListener(ApplicationContextEvent.class)
    public void attachDubboMetadataAndRegistAgain(ApplicationContextEvent event) {
        registrations.forEach((registry, registrations) -> registrations.forEach(registration -> {
            attachDubboMetadataServiceMetadata(registration);
            registry.register(registration);
        }));
    }

    @EventListener(ServiceInstancePreRegisteredEvent.class)
    public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
        Registration registration = event.getSource();
        ServiceRegistry<Registration> registry = event.getRegistry();
        synchronized (registry) {
            registrations.putIfAbsent(registry, new HashSet<>());
            registrations.get(registry).add(registration);
        }
    }

    @EventListener(ServiceInstancePreDeregisteredEvent.class)
    public void onServiceInstancePreDeregistered(ServiceInstancePreDeregisteredEvent event) {
        ServiceRegistry<Registration> registry = event.getRegistry();
        registrations.remove(registry);
    }

    private void attachDubboMetadataServiceMetadata(Registration registration) {
        if (registration == null) {
            return;
        }
        synchronized (registration) {
            Map<String, String> metadata = registration.getMetadata();
            attachDubboMetadataServiceMetadata(metadata);
        }
    }

    private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
        Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
        if (!isEmpty(serviceMetadata)) {
            metadata.putAll(serviceMetadata);
        }
    }

    /*@Configuration(proxyBeanMethods = false)
    @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
    class EurekaConfiguration implements SmartInitializingSingleton {

        @Autowired
        private ObjectProvider<Collection<ServiceBean>> serviceBeans;

        @Order(Ordered.LOWEST_PRECEDENCE - 1)
        @EventListener(ApplicationContextEvent.class)
        public void onServiceInstancePreRegistered(ApplicationContextEvent event) {
            registrations.forEach((registry, registrations) -> registrations.forEach(registration -> {
                EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
                InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
                attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
            }));
        }

        *//**
     * {@link EurekaServiceRegistry} will register current {@link ServiceInstance
     * service instance} on {@link EurekaAutoServiceRegistration#start()} execution(in
     * {@link SmartLifecycle#start() start phase}), thus this method must
     * {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in
     * advance.
     *//*
        @Override
        public void afterSingletonsInstantiated() {
            Collection<ServiceBean> serviceBeans = this.serviceBeans.getIfAvailable();
            if (!isEmpty(serviceBeans)) {
                serviceBeans.forEach(ServiceBean::export);
            }
        }

    }*/

    /*@Configuration(proxyBeanMethods = false)
    @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
    @AutoConfigureOrder
    class ConsulConfiguration {

        @Order(Ordered.LOWEST_PRECEDENCE - 1)
        @EventListener(ApplicationContextEvent.class)
        public void attachURLsIntoMetadataBeforeReRegist(ApplicationContextEvent event) {
            registrations.entrySet().removeIf(entry -> {
                Set<Registration> registrations = entry.getValue();
                registrations.removeIf(registration -> {
                    Class<?> registrationClass = AopUtils.getTargetClass(registration);
                    String registrationClassName = registrationClass.getName();
                    return !CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
                            .equalsIgnoreCase(registrationClassName);
                });
                return registrations.isEmpty();
            });

            registrations.forEach(
                    (registry, registrations) -> registrations.forEach(registration -> {
                        ConsulRegistration consulRegistration = (ConsulRegistration) registration;
                        attachURLsIntoMetadata(consulRegistration);
                    }));
        }

        private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
            NewService newService = consulRegistration.getService();
            Map<String, String> serviceMetadata = dubboServiceMetadataRepository
                    .getDubboMetadataServiceMetadata();
            if (!isEmpty(serviceMetadata)) {
                List<String> tags = newService.getTags();
                for (Map.Entry<String, String> entry : serviceMetadata.entrySet()) {
                    tags.add(entry.getKey() + "=" + entry.getValue());
                }
            }
        }

    }*/

}

之前那两篇文章大致的思路上大致方向是对的,Spring-Cloud-Start-dubbo-2.2.6-RELEASE和Spring-Cloud-Start-dubbo-2.2.7-RELEASE的springBoot的基本流程是一样的,nacos的注册是在在servlet容器启动后进行,dubbo的BootStrap.start()触发是在容器刷新后触发,由于2.3.x的springBoot的版本的容器刷新事件是在nacos的servlet容器启动之后(之前的思路是将dubbo.start()触发提前到nacos注册服务之前,这种是行不通的,因为Spring-Cloud-Start-dubbo的服务注册的start的流程上就有问题,提前这个顺序只会搞出更多的问题),所以就有有dubbo服务还没有注册完,所以就没有触发更新和通知操作

spring-context-5.2.15.RELEASE

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
                //这里是servelet容器启动后会触发通知nacos注册
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
                //这里是触发dubbo启动;
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

finishRefresh();

protected void finishRefresh() {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();
        // 容器刷新时间,触发dubbStrap.start();
		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

start中的服务元数据注册管理:

private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
        Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
        if (!isEmpty(serviceMetadata)) {
            metadata.putAll(serviceMetadata);
        }
    }

getDubboMetadataServiceMetadata方法

public Map<String, String> getDubboMetadataServiceMetadata() {

		List<URL> dubboMetadataServiceURLs = dubboMetadataServiceExporter.export();

		// remove the exported URLs of DubboMetadataService
		removeDubboMetadataServiceURLs(dubboMetadataServiceURLs);

		Map<String, String> metadata = newHashMap();

		addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs);
		addDubboProtocolsPortMetadata(metadata);
		addRevision(metadata);

		return Collections.unmodifiableMap(metadata);
	}

addDubboProtocolsPortMetadata方法

private void addDubboProtocolsPortMetadata(Map<String, String> metadata) {

		allExportedURLs.values().stream().flatMap(v -> v.stream()).forEach(url -> {
			String protocol = url.getProtocol();
			String propertyName = getDubboProtocolPropertyName(protocol);
			String propertyValue = valueOf(url.getPort());
			metadata.put(propertyName, propertyValue);
		});
	}

通过去源码里面找allExportedURLs的逻辑,大致猜测可以知道,当服务注册、变更(刷新)或失败等会有一些触发服务变更通知订阅者的逻辑,这样在只要是服务有变动都可以感知到,然后nacos通知到订阅者,你订阅的服务有变动了,你需要拉取下最新的服务然后更新下本地的服务列表,这个就是我大致的逻辑猜测。

private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>();

4.验证

在公司测试环境依赖使用的是之前升级后的依赖,然后使用上面那个start部署测试环境后,服务提供者部署重启,服务消费者不用重启,然后访问应用,服务消费者可以正常的访问到服务提供者的服务。

5.总结

希望我的分享对你有帮助,有兴趣的可以去看下dubbo的相关源码和具体的逻辑是怎样的,上面的是我的一些猜测(合理的猜想 + 验证),感觉是这么一个感觉,请一键三连,么么么哒!

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

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

相关文章

2023年第二届HiPChips解读

The 2nd International Workshop on High Performance Chiplet and Interconnnect Architectures (HiPChips) 主题 Optical and other advanced chiplet interconnect technologiesInterconnect standards of coherent and non-coherent data sharing protocols (e.g. CXL)D…

美妆护肤品经营小程序商城的作用是什么

美妆护肤品市场非常庞大&#xff0c;属于长期消耗品&#xff0c;对厂家或经营者来说&#xff0c;本质上市场并不缺购买的人&#xff0c;但由于品牌/同行众多&#xff0c;加之消费升级客户线上购物消费&#xff0c;因此传统线下商家发展困难。 但通过线上经营又受制于第三方平台…

9.25 day 2

1. 简述方法重写与方法重载的意义与区别&#xff1a; 方法重写&#xff1a; 1.参数列表必须完全与被重写方法相同 //参数列表&#xff08;分为四种&#xff09;&#xff1a; &#xff08;1&#xff09;无参无返回值方法&#xff1b; &#xff08;2&#xff09;有参无返回…

顺风车软件搭建流程:数字化出行与社会共享的创新

随着移动互联网的快速发展&#xff0c;顺风车软件作为一种新型出行方式逐渐流行起来。本文将介绍顺风车软件搭建的流程&#xff0c;包括需求分析、技术架构设计、用户体验优化以及安全性保障。通过深入思考数字化出行与社会共享的关系&#xff0c;为读者呈现一个专业、有逻辑性…

【Synapse数据集】Synapse数据集介绍和预处理,数据集下载网盘链接

【Segment Anything Model】做分割的专栏链接&#xff0c;欢迎来学习。 【博主微信】cvxiaoyixiao 本专栏为公开数据集的介绍和预处理&#xff0c;持续更新中。 文章目录 1️⃣Synapse数据集介绍文件结构源文件样图文件内容 2️⃣Synapse数据集百度网盘下载链接官网下载登录下…

RocketMQ —消费进度管理

Apache RocketMQ 通过消费位点管理消费进度&#xff0c;本文为您介绍 Apache RocketMQ 的消费进度管理机制。 背景信息​ Apache RocketMQ 的生产者和消费者在进行消息收发时&#xff0c;必然会涉及以下场景&#xff0c;消息先生产后订阅或先订阅后生产。这两种场景下&#x…

【springboot3.x 记录】关于spring-cloud-gateway引入openfeign导致的循环依赖问题

最近升级springboot3真是一挖一个坑&#xff0c;又给我发现了 spring-cloud-gateway 引入 openfeign 会导致循环依赖异常&#xff0c;特此记录一下这个坑 一、发现问题 网关里面有一个全局的过滤器&#xff0c;因为要查询一些配置信息&#xff0c;目前是通过 feign client 的方…

中秋《乡村振兴战略下传统村落文化旅游设计》许少辉八月新书——2023学生思乡季辉少许

中秋《乡村振兴战略下传统村落文化旅游设计》许少辉八月新书——2023学生思乡季辉少许 中秋《乡村振兴战略下传统村落文化旅游设计》许少辉八月新书——2023学生思乡季辉少许

【C++ • STL】探究string的源码

文章目录 一、深浅拷贝二、传统版写法的string类&#xff08;简单&#xff09;三、string类的模拟实现四、现代版写法的string类五、总结 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)&#xff89;" 一、深浅拷贝 浅拷贝&#xff1a;也称位…

数据结构与算法之HashBitMap

一&#xff1a;引入 1.Hash扩容算法在多线程情况有什么问题&#xff1f; 2.如何在3亿个整数&#xff08;0~2亿&#xff09;中判断某一个数是否存在&#xff1f;内存限制500M&#xff0c;一台机器。 分治&#xff1a; 布隆过滤器&#xff1a;神器 Redis Hash: 开3亿个空间&#…

[Go 夜读 第 148 期] Excelize 构建 WebAssembly 版本跨语言支持实践

Excelize 是 Go 语言编写的用于操作电子表格文档的基础库&#xff0c;支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式&#xff0c;高度兼容带有样式、图片 (表)、透视表、切片器等复杂组件的文档&#xff0c;并提供流式读写支持&#xff0c;用于处理包含大规模数据的工…

【项目管理】--敏捷开发管理之Scrum

目录 一、前言二、what---敏捷开发是什么2.1、敏捷开发宣言2.2、敏捷开发原则2.3、一句话概述敏捷开发三、why---为什么会有敏捷开发3.1、传统开发模式和敏捷开发模式对比四、how---敏捷开发怎么实践到项目团队4.1、what---Scrum是什么4.2、what---Scrum有哪些内容(1)、Scrum之…

【C语言练习】DOS黑框框通讯录(使用结构体、动态内存管理联系人信息,函数指针等)

文章目录 1. contacts.h 头文件、函数/常量/结构体声明2. test.c 主界面菜单打印、菜单功能选项选择3. contacts.c 函数实现4. 使用结构体、动态内存&#xff0c;函数指针实现时的注意点5. 运行演示 1. contacts.h 头文件、函数/常量/结构体声明 #pragma once#include <std…

浏览器原生JavaScript离线文字转语音TTS播放,支持Windows自带TTS语音和移动端(安卓、IOS)

前言 JS已经可以实现语音合成(文字转语音)和语音识别(语音转文字),各个浏览器支持列表如下所示: 语音识别支持列表: 因此,浏览器上面使用语音合成非常简单。 页面效果示例: 实现功能 1、支持速度,音调设置 2、支持下拉选择语音模板 3、文字转语音 代码实现 …

自学视觉SLAM(1)

引言 小编研究生的研究方向是视觉SLAM&#xff0c;目前在自学&#xff0c;已经学了Linux系统的基本操作&#xff0c;vim编辑器以及高翔老师的一些视屏。本篇文章为初学笔记。 文章目录 引言1 熟悉 Linux1.1 如何在 Ubuntu 中安装软件&#xff08;命令⾏界⾯&#xff09;&#x…

算法竞赛备赛之动态规划训练提升,DP基础掌握

1.背包问题 1.1.01背包问题 01背包问题是在M件物品中选择若干件放在空间为W的背包中&#xff0c;每件物品的体积为W1&#xff0c;W2至Wn&#xff0c;价值为P1&#xff0c;P2至Pn&#xff0c;01背包的约束条件是给定几种物品&#xff0c;每种物品有且只有一个&#xff0c;并且…

(4) OpenCV图像处理kNN近邻算法-识别数字0和1

我们的目标是构建一个可以读取手写数字的应用程序。为此,我们需要创建一个手写数字的图片文件 “ digits.png ”,图像的像素为:( 320*40 ), 其中包含 32个手写数字(每个数字16个),每个数字都是20x20的图像,如下图。 因此,我们的第 1 步是将图像分割成 32 个不…

华为OD机试 - 第k个排列 - 全排列递归(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

C语言刷题篇(备赛中......)--------( 篇章1 )

前言: 博主报名了一个小比赛&#xff0c;用来写一些基础的C语言题目&#xff0c;正好借此巩固一下基础 希望这些题对你们也有帮助 猫猫跟你说:该学习了 目录 前言: 题目&#xff08; 1 &#xff09; 解题思路 题目&#xff08; 2 &#xff09; 解题思路 题目&#xff…

Linux虚拟机磁盘空间不足怎么办

我是一个目录 1. 在虚拟机客户端扩充磁盘空间2. 检查磁盘空间3. 扩展空间而无需重启虚拟机4. 创建新磁盘分区5. 创建物理卷6. 扩展逻辑卷 对大多数系统管理员来说&#xff0c;扩充 Linux 服务器的磁盘空间是日常的工作之一&#xff0c;下面会通过使用 Linux 命令&#xff0c;在…