Spring Boot Actuator-JMX Endpoints

建议按顺序阅读,请戳《初识篇》《WEB Endpoints


JMX Endpoints,以JMX形式对外提供访问接口。(JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。)


█ 自动配置

 META-INF/spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
  • EndpointAutoConfiguration

公共配置,对于Web EndPoints与JMX EndPoints共用的配置。

@Configuration(proxyBeanMethods = false)
public class EndpointAutoConfiguration {

   // 负责方法参数的转换的参数值映射器
   @Bean
   @ConditionalOnMissingBean
   public ParameterValueMapper endpointOperationParameterMapper(
       // 自动注入被@EndpointConverter标注的Converter与GenericConverter类型的bean
       // Spring Boot Actuator默认没有提供,可自定义添加
         @EndpointConverter ObjectProvider<Converter<?, ?>> converters,
         @EndpointConverter ObjectProvider<GenericConverter> genericConverters) {
      ConversionService conversionService = createConversionService(
            converters.orderedStream().collect(Collectors.toList()),
            genericConverters.orderedStream().collect(Collectors.toList()));
      return new ConversionServiceParameterValueMapper(conversionService);
   }
   // 参数转换器 
   private ConversionService createConversionService(List<Converter<?, ?>> converters,
         List<GenericConverter> genericConverters) {
      // 默认为空,满足if条件       
      if (genericConverters.isEmpty() && converters.isEmpty()) {
         // 添加Spring Boot默认提供的转换器 
         // ApplicationConversionService.getSharedInstance()也会调用new ApplicationConversionService();来添加默认提供的转换器
         return ApplicationConversionService.getSharedInstance();
      }
      // 如果有自定义的转换器,在自定义的基础上,加上Spring Boot默认提供的转化器
      ApplicationConversionService conversionService = new ApplicationConversionService();
      converters.forEach(conversionService::addConverter);
      genericConverters.forEach(conversionService::addConverter);
      return conversionService;
   }

   // 缓存切面,第一次访问后,会将结果缓存起来。下一次再获取直接从缓存中取
   // 可以设置缓存失效时间
   @Bean
   @ConditionalOnMissingBean
   public CachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor(Environment environment) {
      return new CachingOperationInvokerAdvisor(new EndpointIdTimeToLivePropertyFunction(environment));
   }

}

自定义转化器:

@Configuration
public class CustomConversionConfiguration{

    /**
     * 自定义Converter
     * Converter接口是org.springframework.core.convert.converter.Converter
     *
     * 将Integer类型的值转换成String类型
     *
     */
    @Bean
    // 加上注解标注给EndPoint提供服务
    @EndpointConverter
    public Converter<Integer, String> customConverter() {
        return new CustomConverter();
    }

    static class CustomConverter implements Converter<Integer, String>{
        @Override
        public String convert(Integer source) {
            if (source == null) {
                return null;
            }
            return source.toString();
        }
    }

    /**
     *
     * 自定义GenericConverter
     * GenericConverter接口是:org.springframework.core.convert.converter.GenericConverter
     *
     * @return
     */
    @Bean
    // 加上注解标注给EndPoint提供服务
    @EndpointConverter
    public GenericConverter customGenericConverter() {
        return new GenericConverter() {
            @Override
            public Set<ConvertiblePair> getConvertibleTypes() {
                Set<ConvertiblePair> convertiblePairSet = new HashSet<>(2);
                // 将Integer类型的值转换成String类型的值
                convertiblePairSet.add(new ConvertiblePair(Integer.class, String.class));
                return convertiblePairSet;
            }

            @Override
            public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
                // 实现自定义逻辑

                return null;
            }
        };
    }

}
  • JmxEndpointAutoConfiguration

用于JMX EndPoints构建的相关配置。

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(JmxAutoConfiguration.class)
// JmxEndpointProperties:management.endpoints.jmx前缀的配置
@EnableConfigurationProperties(JmxEndpointProperties.class)
// 通过配置 spring.jmx.enabled=false关闭JMX Endpoints功能
@ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true")
public class JmxEndpointAutoConfiguration {

   private final ApplicationContext applicationContext;

   private final JmxEndpointProperties properties;
   // 构造器注入
   public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, JmxEndpointProperties properties) {
      this.applicationContext = applicationContext;
      this.properties = properties;
   }

   // 创建JmxEndpointDiscoverer
   // 根据@EndPoint、@JmxEndPoint标注的类
   @Bean
   @ConditionalOnMissingBean(JmxEndpointsSupplier.class)
   public JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer(ParameterValueMapper parameterValueMapper,
         ObjectProvider<OperationInvokerAdvisor> invokerAdvisors,
         ObjectProvider<EndpointFilter<ExposableJmxEndpoint>> filters) {
      return new JmxEndpointDiscoverer(this.applicationContext, parameterValueMapper,
            invokerAdvisors.orderedStream().collect(Collectors.toList()),
            filters.orderedStream().collect(Collectors.toList()));
   }

   // 创建和暴露JMX服务
   // 参数jmxEndpointsSupplier会自动注入JmxEndpointDiscoverer
   @Bean
   @ConditionalOnSingleCandidate(MBeanServer.class)
   public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, Environment environment,
         ObjectProvider<ObjectMapper> objectMapper, JmxEndpointsSupplier jmxEndpointsSupplier) {
      String contextId = ObjectUtils.getIdentityHexString(this.applicationContext);
      EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory(this.properties, environment,
            mBeanServer, contextId);
      JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(
            objectMapper.getIfAvailable());
      return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper,
            jmxEndpointsSupplier.getEndpoints());

   }
   
   // EndPoint jmx服务暴露过滤器
   // 根据配置:management.endpoints.jmx.exposure.include 设置暴露服务
   // 根据配置:management.endpoints.jmx.exposure.exclude 设置不暴露服务
   @Bean
   public ExposeExcludePropertyEndpointFilter<ExposableJmxEndpoint> jmxIncludeExcludePropertyEndpointFilter() {
      JmxEndpointProperties.Exposure exposure = this.properties.getExposure();
      // 默认暴露所有服务
      return new ExposeExcludePropertyEndpointFilter<>(ExposableJmxEndpoint.class, exposure.getInclude(),
            exposure.getExclude(), "*");
   }

}

█ 创建和暴露服务

在配置类JmxEndpointAutoConfiguration中创建JmxEndpointExporter时:

@Bean
@ConditionalOnSingleCandidate(MBeanServer.class)
public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, Environment environment,
      ObjectProvider<ObjectMapper> objectMapper, JmxEndpointsSupplier jmxEndpointsSupplier) {
   String contextId = ObjectUtils.getIdentityHexString(this.applicationContext);
   EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory(this.properties, environment,
         mBeanServer, contextId);
   JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(
         objectMapper.getIfAvailable());
   return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper,
         jmxEndpointsSupplier.getEndpoints());

}

 创建过程:

jmxEndpointsSupplier.getEndpoints(),jmxEndpointsSupplier会被自动注入JmxEndpointExporter,调用JmxEndpointExporter的getEndpoints,JmxEndpointExporter也是同样继承了EndpointDiscoverer,创建过程和WebEndpointDiscoverer一样,只是重写的createEndpoint创建的ExposableEndpoint类型不同,其返回DiscoveredJmxEndpoint类型:(关于WebEndpointDiscoverer创建过程,请戳《WEB Endpoints》)

@Override
protected ExposableJmxEndpoint createEndpoint(Object endpointBean, EndpointId id, boolean enabledByDefault,
      Collection<JmxOperation> operations) {
   return new DiscoveredJmxEndpoint(this, endpointBean, id, enabledByDefault, operations);
}

 

暴露过程:

new JmxEndpointExporter

return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper,
         jmxEndpointsSupplier.getEndpoints());

(1)JmxEndpointExporter实现了InitializingBean接口,会在Spring初始化Bean的时候,调用afterPropertiesSet方法:

@Override
public void afterPropertiesSet() {
   this.registered = register();
}

(2)register

private Collection<ObjectName> register() {
   return this.endpoints.stream().map(this::register).collect(Collectors.toList());
}

this::register使用的是java8提供的新特性方法引用,即调用JmxEndpointExporter的有参方法register,参数是endpoints集合中的元素,是DiscoveredJmxEndpoint类型。

(3)register(endpoint)

// JmxEndpointExporter#register
private ObjectName register(ExposableJmxEndpoint endpoint) {
   // endpoint是DiscoveredJmxEndpoint 
   Assert.notNull(endpoint, "Endpoint must not be null");
   try {
      ObjectName name = this.objectNameFactory.getObjectName(endpoint);
      // 创建MBean
      EndpointMBean mbean = new EndpointMBean(this.responseMapper, this.classLoader, endpoint);
      // 注册MBean
      this.mBeanServer.registerMBean(mbean, name);
      return name;
   }
   catch (MalformedObjectNameException ex) {
      throw new IllegalStateException("Invalid ObjectName for " + getEndpointDescription(endpoint), ex);
   }
   catch (Exception ex) {
      throw new MBeanExportException("Failed to register MBean for " + getEndpointDescription(endpoint), ex);
   }
}

this.mBeanServer.registerMBean(mbean, name); 这边属于调用JDK提供的API了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值