I've been getting into Spring Statemachine and modelling the state of an Order with it. I read about Guards and Actions, and based on our requirements, a question came up.
What is the correct way of injecting a Spring @Repository or @Service into a Guard or Action?
As described in the docs, Guards and Actions are configured by declaring a @Bean, but I see no way of injecting a @Service or @Repository this way.
For example, take this EnumStateMachineConfigurerAdapter as an example:
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfiguration extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
states
.withStates()
.initial(OrderStates.PENDING)
.initial(OrderStates.APPROVED)
.initial(OrderStates.PAYMENT_REJECTED)
.end(OrderStates.DELIVERED)
.end(OrderStates.CANCELLED)
.end(OrderStates.INVALID)
.end(OrderStates.REFUNDED)
.end(OrderStates.ARCHIVED)
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config) throws Exception {
config
.withConfiguration()
.listener(new StateMachineListener());
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions
.withExternal().source(OrderStates.PENDING).target(OrderStates.APPROVED).event(OrderEvents.APPROVE).and()
... more transitions
}
@Bean
public Guard<OrderStates, OrderEvents> orderIsConsistent() {
return ctx -> {
Order order = ctx.getExtendedState().get(ORDER_KEY, Order.class);
return order.getInconsistencies().isEmpty();
};
}
}
It doesn't seem right to @Autowired a service on top because this is a @Configuration class, not to mention the risk of circular references.
Another solution I came up with is maybe injecting the needed service into the extendedState or a state machine header upon the creation of the state machine and then accessing it via the StateContext?
I'd appreciate some insight on this because I couldn't find an answer in the docs.
You can inject dependencies on method level: