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:
ThreadPoolTaskExecutor
to exisisting managed beans. I've tried but could not succeed.@ManagedOperation
does not work on method level. 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;
}