02 — Getting Started

Auto-Configuration

rulii-spring ships with a single @AutoConfiguration class — RuleConfig — that sets up everything you need. It's registered through Spring Boot's META-INF/spring/AutoConfiguration.imports file, so it activates automatically when the library is on the classpath.

How It Works

Every bean defined by RuleConfig is annotated with @ConditionalOnMissingBean. This means you can override any bean by declaring your own — Spring Boot will skip the default and use yours instead.

Auto-Configured Beans

RuleConfig creates the core beans below, plus four new beans in 2.0.0 (covered afterwards). Here's each one, what it does, and how to replace it.

1. BindingMatchingStrategy

Controls how rule parameters are matched to bindings at runtime. The default uses the standard matching strategy.

@Bean
@ConditionalOnMissingBean(BindingMatchingStrategy.class)
public BindingMatchingStrategy bindingMatchingStrategy() {
    return BindingMatchingStrategy.builder().build();
}

2. ParameterResolver

Resolves method parameters when invoking rule conditions and actions.

@Bean
@ConditionalOnMissingBean(ParameterResolver.class)
public ParameterResolver parameterResolver() {
    return ParameterResolver.builder().build();
}

3. MessageResolver

Resolves messages for rule violations from Spring's Environment. This is a Spring-specific implementation that reads message codes from application.properties.

@Bean
@ConditionalOnMissingBean(MessageResolver.class)
public MessageResolver messageResolver(Environment environment) {
    return new SpringEnvironmentMessageResolver(environment);
}

4. MessageFormatter

Formats resolved message strings, substituting placeholders with runtime values.

@Bean
@ConditionalOnMissingBean(MessageFormatter.class)
public MessageFormatter messageFormatter() {
    return MessageFormatter.builder().build();
}

5. ObjectFactory

Creates rule instances. When Spring's AutowireCapableBeanFactory is available, this uses SpringObjectFactory to enable constructor injection. Otherwise falls back to rulii's default factory.

@Bean(name = BeanNames.OBJECT_FACTORY_NAME)
@ConditionalOnMissingBean(ObjectFactory.class)
public ObjectFactory objectFactory(BeanFactory beanFactory) {
    if (beanFactory instanceof AutowireCapableBeanFactory ctx) {
        return new SpringObjectFactory(ctx);
    }
    return ObjectFactory.builder().build();
}

6. ConverterRegistry

Manages type converters for rule parameters. Automatically picks up any Spring Converter beans and wraps Spring's ConversionService with a SpringConverterAdapter.

@Bean(name = BeanNames.SPRING_CONVERTER_REGISTRY)
@ConditionalOnMissingBean(ConverterRegistry.class)
public ConverterRegistry converterRegistry(
        @Autowired(required = false) Set<Converter<?, ?>> converters,
        @Autowired(required = false) ConversionService conversionService,
        @Value("${rulii.converts.registerDefaults:true}") boolean registerDefaults) {
    // Registers defaults, custom converters, and Spring ConversionService
}

7. RuleRegistry

A Spring-backed registry that looks up rules directly from the application context. Uses SpringRuleRegistry when a ListableBeanFactory is available.

@Bean(BeanNames.RULE_REGISTRY)
@ConditionalOnMissingBean(RuleRegistry.class)
public RuleRegistry ruleRegistry(
        @Autowired(required = false) ListableBeanFactory ctx) {
    if (ctx != null) return new SpringRuleRegistry(ctx);
    return RuleRegistry.builder().build();
}

8. RuleContextOptions

Bundles all the above beans into a single options object for rule execution. Includes a fixed thread pool for async execution and the system clock.

@Bean
@ConditionalOnMissingBean(RuleContextOptions.class)
public RuleContextOptions ruleContextOptions(...) {
    return new SpringEnabledRuleContextOptions(
        matchingStrategy, parameterResolver, messageFormatter,
        converterRegistry, objectFactory, messageResolver,
        Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors())),
        Clock.systemDefaultZone(), Locale.getDefault());
}

9. RuleBeanDefinitionRegistryPostProcessor

A fallback post-processor that automatically scans for rules when @RuleScan is not present. It uses AutoConfigurationPackages to determine the base packages. This bean is only created if no RuleRegistrarMetaInfo bean exists (which @RuleScan registers).

New Beans in 2.0.0

rulii.executorService

A bounded thread pool (work queue of 1000, caller-runs policy) used for async rule and RuleFlow execution, shut down with the application context. It is overridden by name: define your own bean named rulii.executorService to replace it — unrelated ExecutorService beans are deliberately ignored.

Tracer

Auto-configured with every RuliiListener, RuleListener, RuleSetListener, and RuleFlowListener bean found in the context. A bean that implements several listener interfaces is registered exactly once.

ScriptProcessorManager & ScriptTextResolverConfigurer

The script manager wires all discovered ScriptProcessorFactory beans (including SpEL). The resolver configurer enables ${property:default} environment placeholders inside script text; disable it with rulii.scripts.resolvePlaceholders=false.

What Changed in 2.1.0

rulii.executorService Is Now a RuleExecutorService

The rulii.executorService bean is now a RuleExecutorService — the same fixed size, bounded queue of 1000, and caller-runs policy as before, with threads named rulii-exec-N. On context close it stops accepting new work, waits up to rulii.executor.awaitTerminationSeconds (default 10) for running and queued rules to finish, then interrupts what is left. It is still overridden by name: define your own bean named rulii.executorService to replace it.

ScriptProcessorFactoryRegistration

A new bean that registers every ScriptProcessorFactory bean with the JVM-wide ScriptProcessorManager and takes them out again on context destroy, through rulii 2.1's ScriptProcessorManager.unregister. Removal is by identity — a factory a newer context has since registered under the same language is left alone — and names this context had displaced fall back to service-loader discovery. Replaceable with your own bean.

Lifecycle Fix for Child Contexts

SpringRuleRegistry and SpringObjectFactory are now DisposableBeans that release their bean factory from their own container's destroy callback. Closing a child context (Spring Cloud bootstrap, SpringApplicationBuilder.child(), @ContextHierarchy) no longer shuts down the parent's rule infrastructure.

Overriding a Bean

To replace any auto-configured bean, just define your own. For example, to provide a custom MessageResolver:

@Configuration
public class MyRuleConfig {

    @Bean
    public MessageResolver messageResolver() {
        return new MyCustomMessageResolver();
    }
}

Because RuleConfig uses @ConditionalOnMissingBean, your bean takes priority and the default is skipped entirely.