04 — Getting Started
Dependency Injection in Rules
One of the biggest benefits of rulii-spring is that your @Rule classes participate in Spring's dependency injection. You can constructor-inject services, repositories, or any other Spring bean directly into your rules.
SpringObjectFactory
The magic happens in SpringObjectFactory. It extends rulii's DefaultObjectFactory and delegates instance creation to Spring's AutowireCapableBeanFactory.
When the rule engine needs to instantiate a rule class, it calls:
ctx.createBean(ruleClass)
This means every constructor parameter is resolved by Spring, just like any other Spring-managed bean.
Constructor Injection
The recommended pattern is constructor injection. Define your dependencies as constructor parameters and Spring will wire them:
@Rule
public class CreditCheckRule {
private final CreditService creditService;
private final AuditLogger auditLogger;
@Autowired
public CreditCheckRule(CreditService creditService, AuditLogger auditLogger) {
this.creditService = creditService;
this.auditLogger = auditLogger;
}
@Given
public boolean hasSufficientCredit(String customerId, BigDecimal amount) {
return creditService.getAvailableCredit(customerId)
.compareTo(amount) >= 0;
}
@Then
public void approve(String customerId, BigDecimal amount) {
creditService.reserve(customerId, amount);
auditLogger.log("Credit approved for " + customerId);
}
@Otherwise
public void decline(String customerId) {
auditLogger.log("Credit declined for " + customerId);
}
}
Both CreditService and AuditLogger are resolved from the Spring context when the rule is created.
Lifecycle Management
SpringObjectFactory listens for the Spring context's ContextClosedEvent. When the application shuts down, the factory releases its reference to the AutowireCapableBeanFactory, preventing memory leaks. Any attempt to create a rule after shutdown throws a clear exception.
@EventListener
void handleContextRefreshEvent(ContextClosedEvent ctxClosedEvent) {
// Releases reference to prevent stale context usage
this.ctx = null;
}
What You Can Inject
Since rule creation is delegated entirely to Spring's createBean, you can inject anything Spring knows about:
- Your own
@Serviceand@Repositorybeans - Spring Data repositories
Environment,ApplicationContext, and other Spring infrastructure beans- Third-party beans (e.g.,
RestTemplate,WebClient) @Value-annotated configuration properties
Tip
Prefer constructor injection over field injection. It makes your rules easier to test — just pass mocks through the constructor.