1

I've switched from ThreadPoolExecutor to ThreadPoolTaskExecutor in my Spring Boot project just because according to it's documentation:

This class is well suited for management and monitoring (e.g. through JMX)

I've created a bean of ThreadPoolTaskExecutor in my configuration class like this:

  @Bean
  ThreadPoolTaskExecutor profileTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setThreadGroupName(getClass().getSimpleName());
    taskExecutor.setCorePoolSize(corePoolSize);
    taskExecutor.setMaxPoolSize(maxPoolSize);
    taskExecutor.setKeepAliveSeconds(KEEP_ALIVE_MINUTES);
    taskExecutor.setQueueCapacity(1);
    taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    return taskExecutor;
  }

  @Bean
  protected MBeanExporter mbeanExporter() {
    MBeanExporter exporter = new MBeanExporter();
    Map<String, Object> beans = new HashMap<>();
    beans.put("org.springframework.boot:type=Executors,name=ProfileServiceExecutor", profileTaskExecutor());
    exporter.setBeans(beans);
    return exporter;
  }

This runs fine and exposes my ThreadPoolTaskExecutor via JMX. Now the problem is since I'm creating a new MBeanExporter my other ManagedOperations gets overridden and don't show up in JConsole. Now my question is:

  1. Is there a way to add ThreadPoolTaskExecutor to exisisting managed beans. I've tried but could not succeed.
  2. Is this the most efficient way to do this? Isn't there any annotation that I can put on above bean? @ManagedOperation does not work on method level.
Heisenberg
  • 5,514
  • 2
  • 32
  • 43

1 Answers1

2

Here's one way...

@ManagedResource
public class MyExecutor extends ThreadPoolTaskExecutor {

    private static final long serialVersionUID = 1L;

    @ManagedAttribute
    @Override
    public int getCorePoolSize() {
        return super.getCorePoolSize();
    }

    @ManagedAttribute
    @Override
    public int getMaxPoolSize() {
        return super.getMaxPoolSize();
    }

    @ManagedAttribute
    @Override
    public int getKeepAliveSeconds() {
        return super.getKeepAliveSeconds();
    }

    @ManagedAttribute
    @Override
    public int getPoolSize() {
        return super.getPoolSize();
    }

    @ManagedAttribute
    @Override
    public int getActiveCount() {
        return super.getActiveCount();
    }

}

and

@Bean
MyExecutor exec() {
    MyExecutor taskExecutor = new MyExecutor();
    taskExecutor.setThreadGroupName(getClass().getSimpleName());
    taskExecutor.setCorePoolSize(10);
    taskExecutor.setMaxPoolSize(20);
    taskExecutor.setKeepAliveSeconds(5);
    taskExecutor.setQueueCapacity(1);
    taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    return taskExecutor;
}

It will be picked up by boot's exporter.

EDIT

Or, simply override boot's default auto-configured exporter...

@Bean
@Primary
public AnnotationMBeanExporter mbeanExporter(ObjectNamingStrategy namingStrategy,
        Environment environment, BeanFactory beanFactory) {

    AnnotationMBeanExporter exporter = new AnnotationMBeanExporter();
    exporter.setRegistrationPolicy(RegistrationPolicy.FAIL_ON_EXISTING);
    exporter.setNamingStrategy(namingStrategy);
    String serverBean = environment.getProperty("spring.jmx.server",
            "mbeanServer");
    if (StringUtils.hasLength(serverBean)) {
        exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class));
    }
    Map<String, Object> beans = new HashMap<>();
    beans.put("org.springframework.boot:type=Executors,name=ProfileServiceExecutor", profileTaskExecutor());
    exporter.setBeans(beans);
    return exporter;
}
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thank you for your answer. If I do this, don't I need to create the objects of MyExecutor? I would have directly extended `ThreadPoolExecutor` if I wanted that. I used spring's class because they mentioned it's suited for JMX. – Heisenberg Nov 29 '18 at 06:18
  • 1
    Yes; you still need to declare it as a `@Bean`. But you are right you can just extend TPE since the spring TPTE getters simply delegate to that. The comment in the javadocs predates Spring Boot and its auto-configured annotation-based exporter. But you can avoid subclassing by overriding Boot's default exporter - see the edit to my answer. – Gary Russell Nov 29 '18 at 13:51