# Running under Spring
Spring is optional in Moleculer for Java. You never need it to run a service — see A minimal Java service for the framework-free path. Reach for Spring when you want its dependency injection: services that need DAOs, repositories or other Spring components injected, or an existing Spring Boot application you are adding Moleculer to.
The Moleculer
Serviceclass is identical with or without Spring. Actions are the samepublicinstance fields, the lifecycle handlers are the same. Spring only changes who creates the broker and the services — Spring instantiates them as beans and aSpringRegistratorhands them to the broker. The rest of the Core reference applies unchanged.
# How registration works
In a Spring environment, Moleculer Services are Spring beans:
- Mark each service with
@Controller(or@Component) so Spring creates it. - A
services.moleculer.config.SpringRegistratorbean discovers those beans after startup and callsbroker.createService(...)for each. - The
ServiceBrokerbean is started/stopped by Spring viainit-method="start"/destroy-method="stop"— do not also call them yourself.
A Spring-managed service therefore looks exactly like a normal one, plus the stereotype annotation:
package my.services;
import org.springframework.stereotype.Controller;
import services.moleculer.service.*;
@Name("service1")
@Controller
public class TestService extends Service {
@Name("action1")
public Action testAction = ctx ->
ctx.params.get("a", 0) + ctx.params.get("b", 0);
}
The optional REPL, JMX, Web (API Gateway) and MongoDB modules are registered the same way — declare
them as beans and SpringRegistrator wires them into the broker.
# Option A — Spring Boot (Java configuration)
No XML. Put the broker in a @Configuration as a @Bean (Spring starts/stops it via
initMethod/destroyMethod), add a SpringRegistrator, and let component scanning pick up your
@Controller-annotated services. The two classes below are a complete, runnable Java node that
joins the same NATS cluster as a Node.js node — the service1.action1 service from
above becomes callable from Node.js as
broker.call("service1.action1", { a, b }).
// MoleculerApplication.java — the entry point
package my.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({ "my.app", "my.services" }) // scan the broker config and the services
public class MoleculerApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MoleculerApplication.class);
app.setWebApplicationType(WebApplicationType.NONE); // talks over NATS, serves no HTTP
app.run(args);
}
}
// BrokerConfig.java — the broker as a Spring bean
package my.app;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import services.moleculer.ServiceBroker;
import services.moleculer.config.ServiceBrokerConfig;
import services.moleculer.config.SpringRegistrator;
import services.moleculer.serializer.JsonSerializer;
import services.moleculer.transporter.NatsTransporter;
@Configuration
public class BrokerConfig {
// Spring starts the broker (initMethod) and stops it on shutdown (destroyMethod).
@Bean(initMethod = "start", destroyMethod = "stop")
public ServiceBroker serviceBroker() {
ServiceBrokerConfig cfg = new ServiceBrokerConfig();
cfg.setNodeID("java-node"); // unique in the cluster (Node side uses e.g. "node-node")
NatsTransporter nats = new NatsTransporter("nats://localhost:4222"); // the shared bus
nats.setSerializer(new JsonSerializer()); // JSON: the cross-language default
cfg.setTransporter(nats);
// No broker.createService(...) here: the SpringRegistrator below discovers the
// @Controller-annotated services and registers them automatically.
return new ServiceBroker(cfg);
}
// Discovers @Controller/@Component beans of type Service and registers them with the broker.
@Bean
public SpringRegistrator springRegistrator() {
return new SpringRegistrator();
}
}
Add the NATS client (io.nats:jnats) to your pom.xml alongside moleculer-java; see
Setup — one cluster for the dependency block and the cluster-alignment rules.
# Option B — Classic XML configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- ENABLE ANNOTATION PROCESSING -->
<context:annotation-config />
<!-- PACKAGE OF THE MOLECULER SERVICES -->
<context:component-scan base-package="my.services" />
<!-- SPRING REGISTRATOR FOR MOLECULER SERVICES -->
<bean id="registrator"
class="services.moleculer.config.SpringRegistrator"
depends-on="broker" />
<!-- SERVICE BROKER INSTANCE -->
<bean id="broker" class="services.moleculer.ServiceBroker"
init-method="start"
destroy-method="stop">
<constructor-arg ref="brokerConfig" />
</bean>
<!-- SERVICE BROKER SETTINGS -->
<bean id="brokerConfig" class="services.moleculer.config.ServiceBrokerConfig">
<property name="nodeID" value="node-1" />
<property name="transporter" ref="transporter" />
</bean>
<!-- CONFIGURE TRANSPORTER -->
<bean id="transporter" class="services.moleculer.transporter.TcpTransporter" />
</beans>
With this configuration Spring loads Moleculer Services from the my.services package. There is an
extended XML configuration sample (opens new window)
on the project's GitHub page that also shows how to declare internal Moleculer modules in XML.
# Spring init/destroy vs. Moleculer started/stopped
The Moleculer started(broker) / stopped() handlers are always invoked by the ServiceBroker,
not by Spring — so do not register them as Spring init-method / destroy-method. If you also need
Spring init/destroy callbacks, create separate methods for them; the broker lifecycle and the Spring
lifecycle run independently. See Lifecycle.
# Starting and packaging
A Spring Boot Moleculer app can run standalone (Netty) or inside a Jakarta EE servlet container, and is typically launched with the Moleculer Runner. For a minimal, runnable Spring Boot ↔ Node.js interop reference, see the integration demo (opens new window) — a Spring Boot Java node and a Moleculer 0.15 Node.js node on one NATS cluster. The larger Spring Boot demo (opens new window) wires the broker, the Web API Gateway, the REPL and JMX together and ships a Windows installer.