聊聊springcloud的featuresEndpoint

本文主要研究下springcloud的featuresEndpoint

/actuator/features

{
  "enabled": [
    {
      "type": "com.netflix.discovery.EurekaClient",
      "name": "Eureka Client",
      "version": "1.8.8",
      "vendor": null
    },
    {
      "type": "org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient",
      "name": "DiscoveryClient",
      "version": "2.0.0.RC1",
      "vendor": "Pivotal Software, Inc."
    },
    {
      "type": "org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient",
      "name": "LoadBalancerClient",
      "version": "2.0.0.RC1",
      "vendor": "Pivotal Software, Inc."
    },
    {
      "type": "com.netflix.ribbon.Ribbon",
      "name": "Ribbon",
      "version": "2.2.5",
      "vendor": null
    },
    {
      "type": "feign.Feign",
      "name": "Feign",
      "version": null,
      "vendor": null
    }
  ],
  "disabled": []
}

CommonsClientAutoConfiguration

spring-cloud-commons-2.0.0.RC1-sources.jar!/org/springframework/cloud/client/CommonsClientAutoConfiguration.java

@Configuration
@AutoConfigureOrder(0)
public class CommonsClientAutoConfiguration {

    @Configuration
    @EnableConfigurationProperties(DiscoveryClientHealthIndicatorProperties.class)
    @ConditionalOnClass(HealthIndicator.class)
    @ConditionalOnBean(DiscoveryClient.class)
    @ConditionalOnProperty(value = "spring.cloud.discovery.enabled", matchIfMissing = true)
    protected static class DiscoveryLoadBalancerConfiguration {
        @Bean
        @ConditionalOnProperty(value = "spring.cloud.discovery.client.health-indicator.enabled", matchIfMissing = true)
        public DiscoveryClientHealthIndicator discoveryClientHealthIndicator(
                DiscoveryClient discoveryClient, DiscoveryClientHealthIndicatorProperties properties) {
            return new DiscoveryClientHealthIndicator(discoveryClient, properties);
        }

        @Bean
        @ConditionalOnProperty(value = "spring.cloud.discovery.client.composite-indicator.enabled", matchIfMissing = true)
        @ConditionalOnBean(DiscoveryHealthIndicator.class)
        public DiscoveryCompositeHealthIndicator discoveryCompositeHealthIndicator(
                HealthAggregator aggregator, List<DiscoveryHealthIndicator> indicators) {
            return new DiscoveryCompositeHealthIndicator(aggregator, indicators);
        }

        @Bean
        public HasFeatures commonsFeatures() {
            return HasFeatures.abstractFeatures(DiscoveryClient.class,
                    LoadBalancerClient.class);
        }
    }

    @Configuration
    @ConditionalOnClass(Endpoint.class)
    @ConditionalOnProperty(value = "spring.cloud.features.enabled", matchIfMissing = true)
    protected static class ActuatorConfiguration {
        @Autowired(required = false)
        private List<HasFeatures> hasFeatures = new ArrayList<>();

        @Bean
        @ConditionalOnEnabledEndpoint
        public FeaturesEndpoint featuresEndpoint() {
            return new FeaturesEndpoint(this.hasFeatures);
        }
    }

}

这里有一个ActuatorConfiguration,用来注册featuresEndpoint

FeaturesEndpoint

spring-cloud-commons-2.0.0.RC1-sources.jar!/org/springframework/cloud/client/actuator/FeaturesEndpoint.java

@Endpoint(id = "features")
public class FeaturesEndpoint
        implements ApplicationContextAware {

    private final List<HasFeatures> hasFeaturesList;
    private ApplicationContext context;

    public FeaturesEndpoint(List<HasFeatures> hasFeaturesList) {
        this.hasFeaturesList = hasFeaturesList;
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    @ReadOperation
    public Features features() {
        Features features = new Features();

        for (HasFeatures hasFeatures : this.hasFeaturesList) {
            List<Class<?>> abstractFeatures = hasFeatures.getAbstractFeatures();
            if (abstractFeatures != null) {
                for (Class<?> clazz : abstractFeatures) {
                    addAbstractFeature(features, clazz);
                }
            }

            List<NamedFeature> namedFeatures = hasFeatures.getNamedFeatures();
            if (namedFeatures != null) {
                for (NamedFeature namedFeature : namedFeatures) {
                    addFeature(features, namedFeature);
                }
            }
        }

        return features;
    }

    private void addAbstractFeature(Features features, Class<?> type) {
        String featureName = type.getSimpleName();
        try {
            Object bean = this.context.getBean(type);
            Class<?> beanClass = bean.getClass();
            addFeature(features, new NamedFeature(featureName, beanClass));
        }
        catch (NoSuchBeanDefinitionException e) {
            features.getDisabled().add(featureName);
        }
    }

    private void addFeature(Features features, NamedFeature feature) {
        Class<?> type = feature.getType();
        features.getEnabled()
                .add(new Feature(feature.getName(), type.getCanonicalName(),
                        type.getPackage().getImplementationVersion(),
                        type.getPackage().getImplementationVendor()));
    }
    //......
}

这里通过hasFeaturesList来组装两类features,一类是abstractFeatures,另外一类是namedFeatures

HasFeatures

spring-cloud-commons-2.0.0.RC1-sources.jar!/org/springframework/cloud/client/actuator/HasFeatures.java

public class HasFeatures {

    private final List<Class<?>> abstractFeatures = new ArrayList<>();

    private final List<NamedFeature> namedFeatures = new ArrayList<>();

    public static HasFeatures abstractFeatures(Class<?>... abstractFeatures) {
        return new HasFeatures(Arrays.asList(abstractFeatures),
                Collections.<NamedFeature> emptyList());
    }

    public static HasFeatures namedFeatures(NamedFeature... namedFeatures) {
        return new HasFeatures(Collections.<Class<?>> emptyList(),
                Arrays.asList(namedFeatures));
    }

    public static HasFeatures namedFeature(String name, Class<?> type) {
        return namedFeatures(new NamedFeature(name, type));
    }

    public static HasFeatures namedFeatures(String name1, Class<?> type1, String name2,
            Class<?> type2) {
        return namedFeatures(new NamedFeature(name1, type1),
                new NamedFeature(name2, type2));
    }

    public HasFeatures(List<Class<?>> abstractFeatures,
            List<NamedFeature> namedFeatures) {
        this.abstractFeatures.addAll(abstractFeatures);
        this.namedFeatures.addAll(namedFeatures);
    }

    public List<Class<?>> getAbstractFeatures() {
        return this.abstractFeatures;
    }

    public List<NamedFeature> getNamedFeatures() {
        return this.namedFeatures;
    }
}

这里定义了两类features,一类是abstractFeatures,一类是namedFeatures

HasFeatures实例

spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@Import(DiscoveryClientOptionalArgsConfiguration.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
        CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
        "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
        "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"})
public class EurekaClientAutoConfiguration {

    private ConfigurableEnvironment env;

    public EurekaClientAutoConfiguration(ConfigurableEnvironment env) {
        this.env = env;
    }

    @Bean
    public HasFeatures eurekaFeature() {
        return HasFeatures.namedFeature("Eureka Client", EurekaClient.class);
    }
    //......
}

比如eureka的client就注册了一个名为Eureka Client的namedFeature

小结

springcloud提供的featuresEndpoint,可以方便我们查看系统启动的一些features,进而了解系统特征。

doc

  • spring-cloud.html#enabled-features

原文发布于微信公众号 - 码匠的流水账(geek_luandun)

原文发表时间:2018-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java与Android技术栈

用kotlin打造简化版本的ButterKnife

大名鼎鼎的 ButterKnife 库相信很多 android 开发者都听过,在 Github 上star的数目已经快15k了,而且很多知名的app都在使用。

21930
来自专栏MyBlog

关于Valley网络框架

10620
来自专栏猿份到

浅谈Retrofit 源码

现在的项目界面都是按iOS的风格,虽然界面无法发挥出我们大Android的风格,网络框架动不动就是mvp+ okhttp +retrofit+rxjava,m...

36980
来自专栏项勇

笔记69 | Android获取MP3文件的ID3信息工具类

17850
来自专栏刘晓杰

Glide生命周期管理

46380
来自专栏向治洪

android使用LruCache对listview加载图片时候优化处理

注意:LruCache是有版本限制的,低版本的sdk需要在libs文件夹添加相应的support-4v文件。 本文改造的大部分是参考http://www.i...

29960
来自专栏郭耀华‘s Blog

android 一些常用的功能方法代码块

我们这些苦逼的程序员在工作中,每一个老板都希望我们都能把手头的工作做好的,而且是越快越好,那我们要怎么样才能快起来呢?对于开发中常用的代码块无限复做是我们工作...

28340
来自专栏李蔚蓬的专栏

Binary XML file line #19: Attempt to invoke virtual method 'boolean java.lang.String.equals(java....

APP中需要实现LayoutInflater布局加载器动态加载布局,然而开启程序一运行就闪退。。。

22510
来自专栏向治洪

android异步操作

为了使UI在数据获取时不僵死,数据获取需要在新开Worker线程中进行,然后将返回结果在UI线程中进行读取并渲染页面。面对这种异步处理,到底如何写才简洁,先后面...

23180
来自专栏上善若水

032android初级篇之Timer的使用及获取栈顶包名

android 5.0 之后官方屏蔽了获取栈顶信息的api,如下的方法在大多数机器上可用:

14540

扫码关注云+社区

领取腾讯云代金券