HiveMQ Plugins: Spring

HiveMQ Plugins: Spring

author HiveMQ Team

Written by HiveMQ Team

Category: HiveMQ MQTT

Published: January 7, 2016


One of the outstanding features of HiveMQ is the ability to customize the broker with custom Java plugin code, which allows to create virtually every integration you can imagine. Java has one of the best ecosystems in terms of available high quality third-party libraries, so it’s seldom needed to build complex integration functionality from scratch on your own.

The HiveMQ plugin system uses Guice for the dependency injection, which allows to write clean and reusable code. Many popular Java libraries rely on Spring in an intrusive way, though, so sometimes it’s needed to integrate Spring with Guice for your plugins.

There are a few things you have to take care of to use Spring dependency injection in HiveMQ Plugins. As HiveMQ uses Guice for depencendy injection, it is necessary to unterstand when you want Guice to inject something and when you want Spring to handle the injection.

Setting up the Spring ApplicationContext

Since HiveMQ Plugins have their own isolated ClassLoader, you have to setup Springs AplicationContext with a ClassPathXmlApplicationContext. Otherwise Spring won't be able to load your xml file.

Example:

1
2
3
4
5
ClassLoader classLoader = this.getClass().getClassLoader();
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setClassLoader(classLoader);
ctx.setConfigLocation("spring-context.xml");
ctx.refresh();

You also need to setup the ApplicationContext within the configurePlugin() method of your HiveMQPluginModule. This is necessary to make your instances managed by Spring available to Guice. This means you can use Guice to inject Objects created by Spring.

Example:

1
2
3
4
5
protected void configurePlugin() {
    ClassPathXmlApplicationContext ctx = getApplicationContext();
    SpringIntegration.bindAll(binder(), ctx.getBeanFactory());
    bind(ApplicationContext.class).toInstance(ctx);
}

for this to work you also need an additional depency in your pom.xml

1
2
3
4
5
6
7
...
<dependency>
    <groupId>com.google.inject.extensions<groupId>;
    <artifactId>guice-spring</artifactId>
    <version>4.0</version>
</dependency>
.... 

If you want to use Guice to inject instances managed by Spring you need to use the @Named Annotation, because every instance managed by Spring is registered with Guice as a named instance.

Example:

@javax.inject.Inject
@javax.inject.Named("helloWorld")
private HelloWorld helloWorld;

Injecting HiveMQ Plugin Services into Spring instances

If you want to use any of HiveMQ's Services (for example the PublishService), you need to let Guice inject them into your instances.

For this to work with an instance managed by Spring, you cannot use @javax.inject.Inject anywhere in the class (Because Guice and Spring both process this annotation). Instead you should use @Autowired for instances you want to be injected by Spring and @com.google.inject.Inject for the instances you want to be handled by Guice.

Example:

1
2
3
4
5
@org.springframework.beans.factory.annotation.Autowired
private HelloWorld helloWorld;

@com.google.inject.Inject
private PublishService publishService

The next step is to tell Guice to take care of this instance created by Spring. You can do this easily by adding a line to the configurePlugin() method of your HiveMQPluginModule.

Example:

1
2
3
4
// you can also get the bean/singleton by class 
// or any other way which is provided by the BeanFactory
Object o = ctx.getBeanFactory().getBean("myBean");
requestInjection(o);

Register Callbacks managed by Spring

To register your callback implementations with HiveMQ's CallbackRegistry you need to inject them into your PluginEntryPoint by using Guice (even if they are managed by Spring), because the PluginEntryPoint must always be instantiated by Guice.

Remember: Spring managed instances need to be injected with @Named for Guice to recognize them.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class MyPlugin extends PluginEntryPoint {

    //won't work here
    //@Autowired

    @javax.inject.Inject
    @javax.inject.Named("myCallback")
    private MyCallback myCallback;

    @javax.annotation.PostConstruct
    public void postConstruct() {
        getCallbackRegistry().addCallback(myCallback);
    }

}

Example Callback managed by Spring:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Component
public class MyCallback implements OnBrokerStart {
    
    @Autowired
    private HelloWorld helloWorld;
    
    @Override
    public void onBrokerStart() throws BrokerUnableToStartException {
        helloWorld.doStuff();
    }

}

Example Plugin

For a full code example see Github

https://github.com/hivemq/hivemq-spring-example-plugin

author HiveMQ Team

About HiveMQ Team

We love writing about MQTT, IoT protocols and architecture in general. Our experts are here to help, so reach out to us if we can help!

mail icon Contact HiveMQ
newer posts mqtt-spy - HiveMQ MQTT Toolbox
wolfMQTT - MQTT Client Library Encyclopedia older posts