Spring Boot Integration
The transact-spring-boot-starter package integrates DBOS into a Spring Boot application with zero boilerplate: add the dependency, configure a datasource, annotate your beans, and DBOS launches automatically alongside the Spring context.
The Java Widget Store demo is a fully featured DBOS Spring Boot application that illustrates the features described in this documentation.
Adding the Dependency
- Gradle
- Maven
dependencies {
implementation("dev.dbos:transact-spring-boot-starter:1.1.0")
}
<dependencies>
<dependency>
<groupId>dev.dbos</groupId>
<artifactId>transact-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
Configuration
Instead of creating the DBOSConfig for your app programmatically,
the Spring Boot Starter package allows you to configure DBOS via Spring Boot
External Application Properties. For example, you can set your application name and database connection in application.yaml (or application.properties):
dbos:
application:
name: "my-app"
# DBOS system database
datasource:
url: "jdbc:postgresql://localhost:5432/my_app_db"
username: "postgres"
password: "${PGPASSWORD}"
If dbos.application.name or dbos.datasource properties are not set, spring.application.name and spring.datasource are used as a fallback.
spring:
application:
name: "my-app"
datasource:
url: "jdbc:postgresql://localhost:5432/my_app_db"
username: "postgres"
password: "${PGPASSWORD}"
driver-class-name: "org.postgresql.Driver"
DBOS only supports PostgreSQL today. Attempting to use a non PostgreSQL database driver will throw an exception.
For a full list of DBOSConfig fields you can set via application properties, please see the reference documentation.
Programmatic Configuration
Declare a DBOSConfigCustomizer bean to adjust the auto-configured DBOSConfig without replacing it:
@Bean
public DBOSConfigCustomizer myCustomizer() {
return config -> config
.withAdminServer(true)
.withAdminServerPort(8081)
.withEnablePatching(true);
}
Multiple DBOSConfigCustomizer beans are applied in @Order / Ordered order. To replace the config entirely, declare your own @Bean DBOSConfig.
Defining Workflows and Steps
In "vanilla" DBOS, you need to define an interface and a class in order use @Workflow and @Step.
With Spring Boot Starter, you can use the @Workflow and @Step annotations on methods on any Spring-managed singleton bean (@Service, @Component, etc.).
transact-spring-boot-starter uses Spring AOP instead of dynamic proxies, which do not require defining a separate interface.
With Spring Boot Starter, you also don't need to manually register workflow and step proxies with
dbos.registerProxy.
The DBOSWorkflowRegistrar automatically scans all singleton beans after initialization and registers @Workflow methods automatically.
Note, that you do however still need a proxy instance for invocating @Workflow and @Step methods on the same instance.
This proxy reference can be self injected via an @Autowired setter.
@Service
public class OrderService {
private OrderService self;
// self reference is injected automatically by Spring Boot Dependency Injection
@Autowired
@Lazy
public void setSelf(OrderService self) {
this.self = self;
}
@Workflow
public String processOrder(String orderId) {
// Invoke @Step via self reference to perform durable execution book keeping
String result = self.chargeCard(orderId);
self.sendConfirmation(orderId, result);
return result;
}
@Step
public String chargeCard(String orderId) { /* ... */ return "charged"; }
@Step
public void sendConfirmation(String orderId, String result) { /* ... */ }
}
Multiple Beans of the Same Class
When multiple beans of the same class exist, the @Primary one is registered under the default (empty) instance name.
Additional beans of the same class are registered as Workflow Class Instances using their Spring bean name.
To target a specific bean, call startWorkflow through that bean, or pass its bean name as the instance name to the EnqueueOptions constructor: new EnqueueOptions(workflowName, className, beanName, QueueName.of(queue)).
Lifecycle
DBOSLifecycle is a SmartLifecycle bean that calls dbos.launch() after all singletons are initialized and dbos.shutdown() when the context closes, so workflow beans are always registered before launch.
Schedules and queues are stored in the system database and can only be registered once DBOS is launched, so register them in an ApplicationListener<ContextRefreshedEvent> handler, which Spring runs after DBOSLifecycle has started:
@Component
public class QueueSetup implements ApplicationListener<ContextRefreshedEvent> {
@Autowired DBOS dbos;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
dbos.registerQueue("orders", QueueOptions.setWorkerConcurrency(5));
}
}
Injecting dbos instance
The auto-configured DBOS bean is available for injection anywhere in the application:
// Constructor injection
@Service
public class WidgetStoreService {
private final DBOS dbos;
private final WidgetStoreRepository repo;
public WidgetStoreService(DBOS dbos, WidgetStoreRepository widgetStoreRepo) {
this.dbos = dbos;
this.repo = widgetStoreRepo;
}
}
// @Autowired field injection
@Service
public class ScheduleSetup implements ApplicationListener<ContextRefreshedEvent> {
@Autowired DBOS dbos;
@Autowired OrderService orderServiceProxy;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
dbos.applySchedules(
new WorkflowSchedule("daily-orders", "processOrder",
"com.example.OrderService", "0 0 9 * * *")
);
}
}