序
本文主要研究下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, Listindicators) { 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 = 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 ListhasFeaturesList; private ApplicationContext context; public FeaturesEndpoint(List 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 > abstractFeatures = hasFeatures.getAbstractFeatures(); if (abstractFeatures != null) { for (Class clazz : abstractFeatures) { addAbstractFeature(features, clazz); } } List 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> abstractFeatures = new ArrayList<>(); private final List namedFeatures = new ArrayList<>(); public static HasFeatures abstractFeatures(Class ... abstractFeatures) { return new HasFeatures(Arrays.asList(abstractFeatures), Collections. emptyList()); } public static HasFeatures namedFeatures(NamedFeature... namedFeatures) { return new HasFeatures(Collections. > 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 > abstractFeatures, List namedFeatures) { this.abstractFeatures.addAll(abstractFeatures); this.namedFeatures.addAll(namedFeatures); } public List > getAbstractFeatures() { return this.abstractFeatures; } public List 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,进而了解系统特征。