聊聊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

猜你喜欢

转载自my.oschina.net/go4it/blog/1802518