Correct way of injecting a repository or service into Spring statemachine Action and Guard

huangapple go评论86阅读模式
英文:

Correct way of injecting a repository or service into Spring statemachine Action and Guard

问题

我一直在研究Spring Statemachine并使用它对订单的状态进行建模。我阅读了有关“Guards”和“Actions”的内容,并根据我们的需求提出了一个问题。

在Spring中,将`@Repository`或`@Service`注入到“Guard”或“Action”的正确方法是什么?

如[文档][1]中所述,可以通过声明一个`@Bean`来配置“Guard”和“Action”,但我没有看到通过这种方式注入`@Service`或`@Repository`的方法。

例如,以这个`EnumStateMachineConfigurerAdapter`为例:

    @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()
                    ...更多的转换
        }
    
        @Bean
        public Guard<OrderStates, OrderEvents> orderIsConsistent() {
            return ctx -> {
                Order order = ctx.getExtendedState().get(ORDER_KEY, Order.class);
                return order.getInconsistencies().isEmpty();
            };
        }
    }

在顶部进行`@Autowired`似乎不太合适,因为这是一个`@Configuration`类,更不用说循环引用的风险了。

我想到的另一个解决方案是,在创建状态机时将所需的服务注入到“extendedState”或状态机头部,然后通过“StateContext”访问它?

如果文档中没有找到答案,我会非常感谢您提供一些见解。

  [1]: https://docs.spring.io/spring-statemachine/docs/1.1.1.RELEASE/reference/htmlsingle/#configuring-guards
英文:

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&lt;OrderStates, OrderEvents&gt; {

    @Override
    public void configure(StateMachineStateConfigurer&lt;OrderStates, OrderEvents&gt; 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&lt;OrderStates, OrderEvents&gt; config) throws Exception {
        config
                .withConfiguration()
                .listener(new StateMachineListener());
    }

    @Override
    public void configure(StateMachineTransitionConfigurer&lt;OrderStates, OrderEvents&gt; transitions) throws Exception {
        transitions
                .withExternal().source(OrderStates.PENDING).target(OrderStates.APPROVED).event(OrderEvents.APPROVE).and()
                ... more transitions
    }

    @Bean
    public Guard&lt;OrderStates, OrderEvents&gt; orderIsConsistent() {
        return ctx -&gt; {
            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.

答案1

得分: 2

您可以在方法级别上注入依赖项:

@Bean
@Autowired
public Guard<OrderStates, OrderEvents> orderIsConsistent(OrderService orderService) {
    return ctx -> {
        Long orderId = ctx.getExtendedState().get(ORDER_ID, Long.class);
        Order order = orderService.findById(orderId);
        return order.getInconsistencies().isEmpty();
    };
}
英文:

You can inject dependencies on method level:

@Bean
@Autowired
public Guard&lt;OrderStates, OrderEvents&gt; orderIsConsistent(OrderService orderService) {
    return ctx -&gt; {
        Long orderId = ctx.getExtendedState().get(ORDER_ID, Long.class);
        Order order = orderService.findById(orderId);
        return order.getInconsistencies().isEmpty();
    };
}

huangapple
  • 本文由 发表于 2020年10月3日 07:12:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64179206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定