Nacos服务注册源码分析

工程版本

<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR4</spring-cloud.version>

@EnableDiscoveryClient

如果需要将服务注册到注册中心,需要在启动类加上@EnableDiscoveryClient注解,该注解到底有什么作用?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
	// 默认值为true
    // 如果为true,ServiceRegistry将会自动把服务注册到注册中心
	boolean autoRegister() default true;

}

EnableDiscoveryClient源码可以看出该接口有一个autoRegister()方法默认返回值是true,它还引用了EnableDiscoveryClientImportSelector类。

@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
		extends SpringFactoryImportSelector<EnableDiscoveryClient> {
    // 主要看这个方法
	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
		String[] imports = super.selectImports(metadata);
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(
				metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
		boolean autoRegister = attributes.getBoolean("autoRegister");
		if (autoRegister) {
			List<String> importsList = new ArrayList<>(Arrays.asList(imports));
			importsList.add(
					"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
			imports = importsList.toArray(new String[0]);
		}
		else {
			Environment env = getEnvironment();
			if (ConfigurableEnvironment.class.isInstance(env)) {
				ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
				LinkedHashMap<String, Object> map = new LinkedHashMap<>();
				map.put("spring.cloud.service-registry.auto-registration.enabled", false);
				MapPropertySource propertySource = new MapPropertySource(
						"springCloudDiscoveryClient", map);
				configEnv.getPropertySources().addLast(propertySource);
			}

		}
		return imports;
	}
	@Override
	protected boolean isEnabled() {
		return getEnvironment().getProperty("spring.cloud.discovery.enabled",
				Boolean.class, Boolean.TRUE);
	}
	@Override
	protected boolean hasDefaultFactory() {
		return true;
	}

}

主要查看selectImports方法,先获取@EnableDiscoveryClient注解的autoRegister属性。

当autoRegister=true 时,将AutoServiceRegistrationConfiguration 类添加到自动装配中 ,系统就会去自动装配AutoServiceRegistrationConfiguration类,在具体的实现中自动装配类都是在这个AutoServiceRegistrationConfiguration类自动装配完成后才装配的,也就是说autoRegister=true就能够实现服务注册。

当autoRegister=false时,将spring.cloud.service-registry.auto-registration.enabled设置成了 false,跟注册相关的自动配置类就不会生效,因为自动注册相关配置类都有一个条件装配@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)

总结:

默认情况下spring.cloud.service-registry.auto-registration.enabled=true,因此,只要引入了

spring-cloud-starter-alibaba-nacos-discovery依赖,即使启动类上不加@EnableDiscoveryClient注解也会自动向注册中心进行注册。

如果引入了spring-cloud-starter-alibaba-nacos-discovery依赖,又不想将本服务注册到注册中心,注解需要写成@EnableDiscoveryClient(autoRegister = false)

服务注册

Spring Cloud Commons

Spring Cloud 有 Euerka、ZK 等多种注册中心的实现,想要达到实现统一也必须有一套规范,Spring Cloud
Commons 就是约束 Spring Cloud 大部分实现的规范。

spring-cloud-commons
	--org.springframework.cloud
	  --client
        --discovery
        --loadbalancer
        --serviceregistry

Spring Cloud Commons 里面有 Discovery(服务发现)、Load Balancer(负载均衡)、Service Registry(服务注册)等接口的定义。

核心接口

Spring Cloud Commons里面的org.springframework.cloud.client.serviceregistry包下面有 AutoServiceRegistrationRegistrationServiceRegistry这三个接口,这是服务注册的核心接口。

AutoServiceRegistration

AutoServiceRegistration用于服务自动注册。自动注册的意思就是,服务启动后自动把服务信息注册到注册中心。

public interface AutoServiceRegistration {

}

AutoServiceRegistration没有定义方法,它的存在就是要规范实现必须要有自动注册。

Registration

Registration存储服务信息,用于规范将什么信息注册到注册中心。

public interface Registration extends ServiceInstance {

}

Registration继承 ServiceInstanceServiceInstance定义了一个服务实例应该具有什么信息。

ServiceInstance

public interface ServiceInstance {
	/**
	 * 实例的唯一标识
	 * @return The unique instance ID as registered.
	 */
	default String getInstanceId() {
		return null;
	}
	/**
	 * 服务名称
	 * @return The service ID as registered.
	 */
	String getServiceId();
	/**
	 * 主机地址
	 * @return The hostname of the registered service instance.
	 */
	String getHost();
	/**
	 * 端口号
	 * @return The port of the registered service instance.
	 */
	int getPort();
	/**
	 * 是否是HTTPS
	 * @return Whether the port of the registered service instance uses HTTPS.
	 */
	boolean isSecure();
	/**
	 * 服务URI地址
	 * @return The service URI address.
	 */
	URI getUri();
	/**
	 * 服务的元数据信息,如果我们需要给服务携带上其他额外的信息,就可以保存在这个里面
	 * @return The key / value pair metadata associated with the service instance.
	 */
	Map<String, String> getMetadata();
	/**
	 * @return The scheme of the service instance.
	 */
	default String getScheme() {
		return null;
	}

}

ServiceRegistry

ServiceRegistry是服务注册接口,用来向注册中心注册服务。

public interface ServiceRegistry<R extends Registration> {
	/**
	 * Registers the registration. A registration typically has information about an
	 * instance, such as its hostname and port.
	 * @param registration registration meta data
	 */
    // 注册服务
	void register(R registration);

	/**
	 * Deregisters the registration.
	 * @param registration registration meta data
	 */
    // 反注册
	void deregister(R registration);

	/**
	 * Closes the ServiceRegistry. This is a lifecycle method.
	 */
    // 关闭
	void close();

	/**
	 * Sets the status of the registration. The status values are determined by the
	 * individual implementations.
	 * @param registration The registration to update.
	 * @param status The status to set.
	 * @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
	 */
    // 设置服务状态
	void setStatus(R registration, String status);

	/**
	 * Gets the status of a particular registration.
	 * @param registration The registration to query.
	 * @param <T> The type of the status.
	 * @return The status of the registration.
	 * @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
	 */
    // 获取服务状态
	<T> T getStatus(R registration);

}

Nacos服务注册

Nacos将服务注册到注册中心,主要涉及如下几个类:

NacosRegistration:保存服务的基本数据信息

NacosServiceRegistry:实现服务注册

NacosServiceRegistryAutoConfiguration:Nacos自动配置类

NacosRegistration

该类主要是管理服务的一些基本数据,如服务名,服务ip地址等信息。它实现了spring-cloud-commons 提供的RegistrationServiceInstance接口。

public class NacosRegistration implements Registration, ServiceInstance {
	/**
	 * The metadata key of management port.
	 */
	public static final String MANAGEMENT_PORT = "management.port";
	/**
	 * The metadata key of management context-path.
	 */
	public static final String MANAGEMENT_CONTEXT_PATH = "management.context-path";
	/**
	 * The metadata key of management address.
	 */
	public static final String MANAGEMENT_ADDRESS = "management.address";
	/**
	 * The metadata key of management endpoints web base path.
	 */
	public static final String MANAGEMENT_ENDPOINT_BASE_PATH = "management.endpoints.web.base-path";

	private NacosDiscoveryProperties nacosDiscoveryProperties;

	private ApplicationContext context;

    // 构造函数
	public NacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,
			ApplicationContext context) {
		this.nacosDiscoveryProperties = nacosDiscoveryProperties;
		this.context = context;
	}
}

NacosServiceRegistry

该类实现了 spring-cloud-commons 提供的 ServiceRegistry接口,在register方法中主要是将配置文件封装成Instance实例,调用了namingService.registerInstance(serviceId, instance)方法将服务注册到注册中心。

public class NacosServiceRegistry implements ServiceRegistry<Registration> {

	private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);

	private final NacosDiscoveryProperties nacosDiscoveryProperties;

    // 这个是用来与注册中心进行通信的,如注册服务到nacos注册中心
	private final NamingService namingService;

	public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
		this.nacosDiscoveryProperties = nacosDiscoveryProperties;
		this.namingService = nacosDiscoveryProperties.namingServiceInstance();
	}

    // 服务注册
	@Override
	public void register(Registration registration) {
		if (StringUtils.isEmpty(registration.getServiceId())) {
			log.warn("No service to register for nacos client...");
			return;
		}
		String serviceId = registration.getServiceId();
		String group = nacosDiscoveryProperties.getGroup();
        // 将 Registration 转换成 Instance
		Instance instance = getNacosInstanceFromRegistration(registration);
		try {
            // 将服务注册到注册中心
            // 这个方法里面的底层还是发送http请求完成注册
			namingService.registerInstance(serviceId, group, instance);
			log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
					instance.getIp(), instance.getPort());
		}
		catch (Exception e) {
			log.error("nacos registry, {} register failed...{},", serviceId,
					registration.toString(), e);
			// rethrow a RuntimeException if the registration is failed.
			// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
			rethrowRuntimeException(e);
		}
	}
    // 省略其它方法
}

Nacos自动配置类

NacosServiceRegistryAutoConfiguration自动配置类

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
// 向nacos注册中心注册服务开关,默认是true
@ConditionalOnNacosDiscoveryEnabled
// 自动注册开关,默认是true
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
		AutoServiceRegistrationAutoConfiguration.class,
		NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {

	@Bean
	public NacosServiceRegistry nacosServiceRegistry(
			NacosDiscoveryProperties nacosDiscoveryProperties) {
		return new NacosServiceRegistry(nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosRegistration nacosRegistration(
			NacosDiscoveryProperties nacosDiscoveryProperties,
			ApplicationContext context) {
		return new NacosRegistration(nacosDiscoveryProperties, context);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosAutoServiceRegistration nacosAutoServiceRegistration(
			NacosServiceRegistry registry,
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,
			NacosRegistration registration) {
		return new NacosAutoServiceRegistration(registry,
				autoServiceRegistrationProperties, registration);
	}

}

这个自动配置类主要是往容器中注入了NacosServiceRegistryNacosRegistrationNacosAutoServiceRegistration

NacosAutoServiceRegistration是用来触发服务注册行为的。查看NacosAutoServiceRegistration源码可以发现,NacosAutoServiceRegistration实现了ApplicationListener接口,项目启动成功后会调用ApplicationListeneronApplicationEvent(WebServerInitializedEvent event)方法,通过这里最终会调用ServiceRegistry.register(R registration)方法将服务注册到注册中心。

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class App1Test {
    @Autowired
    private SpringClientFactory springClientFactory;

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Autowired
    private NacosServiceRegistry nacosServiceRegistry;
    
    @Test
    public void test1() throws NacosException {
        NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
        List<Instance> allInstances = namingService.getAllInstances("app1");
        NamingMaintainService namingMaintainService = nacosDiscoveryProperties.namingMaintainServiceInstance();
        for (Instance instance : allInstances) {
            instance.addMetadata("username",new Random().nextInt(1000000)+"");
            namingMaintainService.updateInstance("app1",instance);
        }
    }

    @Test
    public void test2() throws NacosException {
        ILoadBalancer loadBalancer = springClientFactory.getLoadBalancer("app1");
    }
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值