SpringCloud中@EnableDiscoveryClient的源码解析

// 核心作用
// 导入具体的DiscoveryClient实现,例如: NacosDiscoveryClient
// DiscoveryClient: 可以获取所有实例信息,实例ID列表
@EnableDiscoveryClient
public class App {
}

@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
    // 如果为true, ServiceRegistry将自动注册本地服务器
    boolean autoRegister() default true;
}

@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> {

    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        // 从Spring.factories文件中加载EnableDiscoveryClient类型的数据导入
        String[] imports = super.selectImports(metadata);
        // 获取EnableDiscoveryClient注解信息
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
        // 获取自动注册标识
        boolean autoRegister = attributes.getBoolean("autoRegister");
        // 如果是自动注册
        if (autoRegister) {
            // 导入工厂类以及自动注册的配置类
            List<String> importsList = new ArrayList<>(Arrays.asList(imports));
            /**
             * {@link AutoServiceRegistrationConfiguration}
             */
            importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
            imports = importsList.toArray(new String[0]);
        } else {
            // 如果不是自动注册
            Environment env = getEnvironment();
            if (env instanceof ConfigurableEnvironment configEnv) {
                LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                // 设置自动注册的属性值为false
                map.put("spring.cloud.service-registry.auto-registration.enabled", false);
                // 将该属性添加到上下文环境对象中
                MapPropertySource propertySource = new MapPropertySource("springCloudDiscoveryClient", map);
                configEnv.getPropertySources().addLast(propertySource);
            }

        }

        return imports;
    }

    // 开启标识: spring.cloud.discovery.enabled,默认为true
    @Override
    protected boolean isEnabled() {
        return getEnvironment().getProperty("spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
    }

    // 存在默认的工厂类,能处理该注解,说明存在默认处理DiscoveryClient的类
    // 默认为: SimpleDiscoveryClient,如果导入了其他的DiscoveryClient依赖,那么就会存在对应的DiscoveryClient实现
    // 例如: Nacos -> NacosDiscoveryClient
    @Override
    protected boolean hasDefaultFactory() {
        return true;
    }

}

public abstract class SpringFactoryImportSelector<T> implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {

    // Bean的类加载器
    private ClassLoader beanClassLoader;
    // 处理的注解类型(@EnableDiscoveryClient)
    private Class<T> annotationClass;
    // 上下文环境对象
    private Environment environment;

    protected SpringFactoryImportSelector() {
        // 类中的泛型注解信息(@EnableDiscoveryClient)
        this.annotationClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
    }

    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        // 如果没有开启,不处理
        if (!this.isEnabled()) {
            return new String[0];
        }
        // 获取注解的属性信息
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
        /**
         * 例如: 类似与这种效果,但是也可以通过其他方式,核心就是导入DiscoveryClient的实现
         * <pre>
         * org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
         *  org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration,\
         *  org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
         *  org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
         *  org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration,\
         *  com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
         *  org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClientConfiguration,\
         *</pre>
         */
        // 从Spring.factories文件中加载EnableDiscoveryClient为Key的自动配置类
        List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
        // 如果为空并且不包含默认的处理DiscoveryClient的工厂类,抛出异常,意思是: 找到注解找不到DiscoveryClient实现
        if (factories.isEmpty() && !hasDefaultFactory()) {
            throw new IllegalStateException("Annotation @" + getSimpleName() + " found, but there are no implementations. Did you forget to include a starter?");
        }
        // 应该只有一个DiscoveryClient,但可能不止一个处理DiscoveryClient的工厂
        if (factories.size() > 1) {
            this.log.warn("More than one implementation " + "of @" + getSimpleName() + " (now relying on @Conditionals to pick one): " + factories);
        }
        // 导入从Spring.factories文件中加载EnableDiscoveryClient类型的数据
        return factories.toArray(new String[factories.size()]);
    }


    // 给子类重写
    // 默认不存在工厂类,无法处理该注解
    protected boolean hasDefaultFactory() {
        return false;
    }

    protected abstract boolean isEnabled();

}

@Configuration(proxyBeanMethods = false)
// 导入自动注册的配置类
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
// spring.cloud.service-registry.auto-registration.enabled开启则导入AutoServiceRegistrationProperties配置类,默认为true
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {

}
// 导入了依赖,会自动注册DiscoveryClient的实现,下面是各种实现之一
// org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
//        org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration,\
//        org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
//        org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
//        org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration,\
//        com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
//        org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClientConfiguration,\

// 解析DiscoveryClient配置类,以Nacos为例
@Configuration(proxyBeanMethods = false)
// 对应的spring.cloud.discovery.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnDiscoveryEnabled
// 对应的spring.cloud.discovery.blocking.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnBlockingDiscoveryEnabled
// 对应的spring.cloud.nacos.discovery.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnNacosDiscoveryEnabled
// SimpleDiscoveryClientAutoConfiguration和CommonsClientAutoConfiguration需要在当前类加载之前加载
// 因为这两个配置是默认的提供的实现配置
@AutoConfigureBefore({SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class})
// NacosDiscoveryAutoConfiguration需要在当前类加载之后再进行加载
@AutoConfigureAfter(NacosDiscoveryAutoConfiguration.class)
public class NacosDiscoveryClientConfiguration {

    // 导入Nacos的服务发现客户端实现
    @Bean
    public DiscoveryClient nacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
        return new NacosDiscoveryClient(nacosServiceDiscovery);
    }


    // 导入Nacos的监控类
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", matchIfMissing = false)
    public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties);
    }

    // 网关心跳检测的事件发布器
    // 使用定时线程池,在固定的时间间隔,发送心跳包
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(value = "spring.cloud.gateway.discovery.locator.enabled", matchIfMissing = false)
    public GatewayLocatorHeartBeatPublisher gatewayLocatorHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new GatewayLocatorHeartBeatPublisher(nacosDiscoveryProperties);
    }

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {

    @Bean
    public NacosServiceManager nacosServiceManager() {
        return new NacosServiceManager();
    }

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public NacosDiscoveryProperties nacosProperties() {
        return new NacosDiscoveryProperties();
    }

    @Bean
    @ConditionalOnMissingBean
    public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
        return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
    }

}

// Nacos服务发现
public class NacosServiceDiscovery {

    // Nacos服务发现配置属性
    private NacosDiscoveryProperties discoveryProperties;
    // Nacos服务管理器
    private NacosServiceManager nacosServiceManager;

    public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
        this.discoveryProperties = discoveryProperties;
        this.nacosServiceManager = nacosServiceManager;
    }

    // 根据实例ID返回所有的实例对象
    public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
        String group = discoveryProperties.getGroup();
        List<Instance> instances = namingService().selectInstances(serviceId, group, true);
        // 将Nacos的实例信息转换为SpringCloud规定的实例信息
        return this.hostToServiceInstanceList(instances, serviceId);
    }

    // 返回所有的实例名称
    public List<String> getServices() throws NacosException {
        String group = discoveryProperties.getGroup();
        ListView<String> services = namingService().getServicesOfServer(1, Integer.MAX_VALUE, group);
        return services.getData();
    }

    // 将Nacos的实例信息转换为SpringCloud规定的实例信息
    public static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) {
        List<ServiceInstance> result = new ArrayList<>(instances.size());
        // 遍历Nacos的实例信息
        for (Instance instance : instances) {
            // 将Nacos的实例信息转换为SpringCloud规定的实例信息
            ServiceInstance serviceInstance = this.hostToServiceInstance(instance, serviceId);
            if (serviceInstance != null) {
                result.add(serviceInstance);
            }
        }
        return result;
    }

    // 将Nacos的实例信息转换为SpringCloud规定的实例信息
    public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
        if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {
            return null;
        }
        NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
        nacosServiceInstance.setHost(instance.getIp());
        nacosServiceInstance.setPort(instance.getPort());
        nacosServiceInstance.setServiceId(serviceId);
        nacosServiceInstance.setInstanceId(instance.getInstanceId());
        Map<String, String> metadata = new HashMap<>();
        metadata.put("nacos.instanceId", instance.getInstanceId());
        metadata.put("nacos.weight", instance.getWeight() + "");
        metadata.put("nacos.healthy", instance.isHealthy() + "");
        metadata.put("nacos.cluster", instance.getClusterName() + "");
        if (instance.getMetadata() != null) {
            metadata.putAll(instance.getMetadata());
        }
        metadata.put("nacos.ephemeral", String.valueOf(instance.isEphemeral()));
        nacosServiceInstance.setMetadata(metadata);
        if (metadata.containsKey("secure")) {
            boolean secure = Boolean.parseBoolean(metadata.get("secure"));
            nacosServiceInstance.setSecure(secure);
        }
        return nacosServiceInstance;
    }

    // 获取Nacos的名称服务对象,该对象负责管理所有的服务实例,包括注册,取消注册
    private NamingService namingService() {
        return nacosServiceManager.getNamingService();
    }

}

// Nacos的服务发现客户端
public class NacosDiscoveryClient implements DiscoveryClient {

    public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";

    // Nacos的服务发现
    private NacosServiceDiscovery serviceDiscovery;

    // 是否启用容错机制,默认为false
    @Value("${spring.cloud.nacos.discovery.failure-tolerance-enabled:false}")
    private boolean failureToleranceEnabled;

    public NacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
        this.serviceDiscovery = nacosServiceDiscovery;
    }

    @Override
    public String description() {
        return DESCRIPTION;
    }

    @Override
    public List<ServiceInstance> getInstances(String serviceId) {
        try {
            // 根据服务ID获取实例
            return Optional.of(serviceDiscovery.getInstances(serviceId))
                    // 如果获取到了,缓存起来
                    .map(instances -> {
                        ServiceCache.setInstances(serviceId, instances);
                        return instances;
                    }).get();
        } catch (Exception e) {
            // 如果获取失败,开启了容错机制,从缓存中获取服务实例
            if (failureToleranceEnabled) {
                return ServiceCache.getInstances(serviceId);
            }
            // 如果没有开启容错,抛出异常
            throw new RuntimeException("Can not get hosts from nacos server. serviceId: " + serviceId, e);
        }
    }

    // 获取服务名称ID
    @Override
    public List<String> getServices() {
        try {
            // 从服务发现中获取所有的实例ID,并缓存起来
            return Optional.of(serviceDiscovery.getServices()).map(services -> {
                ServiceCache.setServiceIds(services);
                return services;
            }).get();
        } catch (Exception e) {
            // 获取的过程发生异常
            // 如果开启了容器机制,返回缓存中的实例ID,否则返回空实例ID
            log.error("get service name from nacos server failed.", e);
            return failureToleranceEnabled ? ServiceCache.getServiceIds() : Collections.emptyList();
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值