spring-cloud-alibaba-dubbo-issues1805修复

spring-cloud-alibaba-dubbo-issues1805修复

这个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的相关源码和具体的逻辑是怎样的,上面的是我的一些猜测(合理的猜想 + 验证),感觉是这么一个感觉,请一键三连,么么么哒!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
`spring-cloud-alibaba-dependencies`是一个Maven BOM(Bill of Materials),包含了Spring Cloud Alibaba的所有依赖版本。通过引入`spring-cloud-alibaba-dependencies`,可以简化Spring Cloud Alibaba项目的依赖管理。它提供了以下依赖: - `spring-cloud-alibaba-dependencies`:Spring Cloud Alibaba版本管理器 - `spring-cloud-starter-alibaba-nacos-discovery`:Nacos服务发现 - `spring-cloud-starter-alibaba-nacos-config`:Nacos配置中心 - `spring-cloud-starter-alibaba-sentinel`:Sentinel限流熔断 - `spring-cloud-starter-alibaba-seata`:Seata分布式事务 - `spring-cloud-starter-alibaba-rocketmq`:RocketMQ消息队列 - `spring-cloud-starter-alibaba-dubbo`:Dubbo远程调用 使用`spring-cloud-alibaba-dependencies`需要在`pom.xml`文件中引入如下配置: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` 引入该依赖后,其他Spring Cloud Alibaba组件的依赖版本就可以省略了。例如,使用Nacos作为服务发现和配置中心,只需要引入以下依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> ``` Spring Cloud Alibaba会自动使用`spring-cloud-alibaba-dependencies`中定义的版本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值