spring-bootspring-boot-actuatorspring-jmx

spring boot actuator connect jmx programmatically


I'd like to use the shutdown endpoint of my Spring Boot 2.0.1 application from the command line. For that I have only added the spring-boot-starter-actuator to my Gradle file and enabled the shutdown endpoint in the configuration.

I also created a very simple tool that tries to connect via JMX to the running application.

Snippet:

String url = "service:jmx:rmi:///jndi/rmi://127.0.01:<which port?>/jmxrmi";
JMXServiceURL serviceUrl = new JMXServiceURL(url);
JMXConnectorFactory.connect(serviceUrl, null); <-- KAPOW!

JMX is working because I can use jconsole to connect locally. I just have no clue how to do it programmatically.

Any other attempts to explicitly set a port as mentioned here didn't work. Any hints?


Solution

  • It's probably easier to enable jolokia rather than using RMI; then you can simply

    curl http://localhost:8080/actuator/jolokia/exec/org.springframework.boot:type=Admin,name=SpringApplication/shutdown
    

    EDIT

    If you prefer to use RMI, refer to the Spring Framework JMX Documentation.

    Server app:

    @SpringBootApplication
    public class So50392589Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So50392589Application.class, args);
        }
    
        @Bean
        public RmiRegistryFactoryBean rmi() {
            RmiRegistryFactoryBean rmi = new RmiRegistryFactoryBean();
            rmi.setPort(1099);
            return rmi;
        }
    
        @Bean
        public ConnectorServerFactoryBean server() throws Exception {
            ConnectorServerFactoryBean fb = new ConnectorServerFactoryBean();
            fb.setObjectName("connector:name=rmi");
            fb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector");
            return fb;
        }
    
    }
    

    Client app:

    @SpringBootApplication
    public class JmxClient {
    
        public static void main(String[] args) {
            new SpringApplicationBuilder(JmxClient.class)
                .web(WebApplicationType.NONE)
                .run(args);
        }
    
        @Bean
        public ApplicationRunner runner(MBeanServerConnection jmxConnector) {
            return args -> {
                jmxConnector.invoke(new ObjectName("org.springframework.boot:type=Admin,name=SpringApplication"),
                        "shutdown", new Object[0], new String[0]);
            };
        }
    
        @Bean
        public MBeanServerConnectionFactoryBean jmxConnector() throws Exception {
            MBeanServerConnectionFactoryBean jmx = new MBeanServerConnectionFactoryBean();
            jmx.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector");
            return jmx;
        }
    
    }