Обнаружение bean-компонентов Spring State Machine не работает

В настоящее время я создаю небольшой образец проекта с конечным автоматом Spring.

Моя конфигурация:

@Configuration
@EnableStateMachine
public class StateMachineConfiguration extends EnumStateMachineConfigurerAdapter<States, Events> {

    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states)
            throws Exception {
        states
                .withStates()
                .initial(States.LOCKED)
                .states(EnumSet.allOf(States.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
            throws Exception {
        transitions
                .withExternal()
                .source(States.LOCKED)
                .target(States.UNLOCKED)
                .event(Events.COIN)
                .and()
                .withExternal()
                .source(States.UNLOCKED)
                .target(States.LOCKED)
                .event(Events.PUSH);
    }

    @Bean
    public StateMachineListener<States, Events> listener() {
        return new StateMachineListenerAdapter<States, Events>() {
            @Override
            public void stateChanged(State<States, Events> from, State<States, Events> to) {
                System.out.println("State change to " + to.getId());
            }
        };
    }
}

Когда я сейчас пытаюсь ввести конечный автомат с помощью

@Autowired
StateMachine<States, Events> stateMachine;

IntelliJ дает мне подсказку, что это не может быть проводной, потому что там нет bean-компонента. Я также получаю исключение, если запускаю Приложение.

Зависимость gradle:

compile 'org.springframework.statemachine:spring-statemachine-core:2.0.1.
compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.0.1.RELEASE'
compile group: 'org.springframework.shell', name: 'spring-shell-starter', version: '2.0.1.RELEASE'
compile group: 'org.springframework.statemachine', name: 'spring-statemachine-boot', version: '1.2.11.RELEASE'

Вы решили проблему?

sean hawk 25.08.2018 00:10

@seanhawk проверить мой пост

Daniel Eisenreich 21.11.2018 19:53

@DanielEisenreich в коде, если вы измените аннотацию @EnableStateMachine на @EnableStateMachineFactory, это сработает. Спасибо.

Arefe 27.02.2021 02:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
3
2 132
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вы можете попробовать использовать

@EnableStateMachine(name = "myStateMachine")

а также

@Autowired
StateMachine<States, Events> myStateMachine;

Для меня это не работает.

skyho 30.11.2020 16:01
Ответ принят как подходящий

Я не знаю, в чем была проблема ... Но следующий фрагмент мне подходит.

@Configuration
@EnableStateMachine
public class StateMachineConfiguration {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Bean
    public StateMachine<States, Events> stateMachine(StateMachineListener<States, Events> listener) throws Exception {
        StateMachineBuilder.Builder<States, Events> builder = StateMachineBuilder.builder();

        builder.configureStates()
            .withStates()
            .initial(States.LOCKED)
            .states(EnumSet.allOf(States.class));

        builder.configureTransitions()
            .withExternal()
            .source(States.LOCKED)
            .target(States.UNLOCKED)
            .event(Events.COIN)
            .and()
            .withExternal()
            .source(States.UNLOCKED)
            .target(States.LOCKED)
            .event(Events.PUSH);

        StateMachine<States, Events> stateMachine = builder.build();
        stateMachine.addStateListener(listener);
        return stateMachine;
    }

    @Bean
    public StateMachineListener<States, Events> listener() {
        return new StateMachineListenerAdapter<States, Events>() {
            @Override
            public void stateChanged(State<States, Events> from, State<States, Events> to) {
                logger.info("State change to " + to.getId());
            }
        };
    }
}

Фрагмент работает, потому что вы создаете StateMachine @Bean самостоятельно. Intellij может его найти. Тем не менее, если StateMachine - это @Autowired, Spring автоматически создаст экземпляр bean-компонента StateMachine по умолчанию, если он не был определен как @Bean. Кредит принадлежит @guidadic, но он пока не может комментировать сообщения других пользователей.

Andrei Konstantinov 02.06.2019 00:54

Кроме того, у вас может быть такая ошибка: The bean 'stateMachine' could not be registered. A bean with that name has already been defined in class path resource [com/tests/springboottests/stateMachine/StateMachineConfig.c‌​lass] and overriding is disabled. Решение для этого: spring.main.allow-bean-definition-overriding=true в application.properties

Evghenii Orenciuc 15.03.2020 12:01

Для меня проблема была вызвана несоответствием параметров универсального типа. Поэтому вместо StateMachineStateConfigurer у меня был StateMachineStateConfigurer, поэтому версия bean-компонента не была определена.

В вашем случае проверьте импорт «Состояния» и импорт «События», чтобы убедиться, что это те же классы в определении bean-компонента и в том месте, где вы его используете с @Autowired.

У меня та же проблема.

Я сделал это.

Это работает

@SpringBootApplication
@EnableStateMachine
public class StateMachineSpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(StateMachineSpringBootApplication.class, args);
    }

}

config

@Configuration
public class MachineConfigurationCustom extends EnumStateMachineConfigurerAdapter<BookStates, BookEvents> {

    @Bean
    public StateMachine<BookStates, BookEvents> stateMachine(StateMachineListener<BookStates, BookEvents> listener) throws Exception {

        StateMachineBuilder.Builder<BookStates, BookEvents>  builder =
                StateMachineBuilder.builder();

        builder.configureStates()
                .withStates()
                .initial(BookStates.AVAILABLE)
                .states(EnumSet.allOf(BookStates.class));

        builder.configureTransitions()
                .withExternal()
                .source(BookStates.AVAILABLE)
                .target(BookStates.BORROWED)
                .event(BookEvents.BORROW)
                .and()
                .withExternal()
                .source(BookStates.BORROWED)
                .target(BookStates.AVAILABLE)
                .event(BookEvents.RETURN)
                .and()
                .withExternal()
                .source(BookStates.AVAILABLE)
                .target(BookStates.IN_REPAIR)
                .event(BookEvents.START_REPAIR)
                .and()
                .withExternal()
                .source(BookStates.IN_REPAIR)
                .target(BookStates.AVAILABLE)
                .event(BookEvents.END_REPAIR);

        StateMachine<BookStates, BookEvents> stateMachine = builder.build();
        stateMachine.addStateListener(listener);
        return stateMachine;
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<BookStates, BookEvents> config) throws Exception {
        config.withConfiguration()
                .autoStartup(true)
                .listener(new LoggingMachineListener());
    }


}

слушатель

@Component
public class LoggingMachineListener implements StateMachineListener<BookStates, BookEvents> {
    private static final Logger LOGGER = LoggingUtils.LOGGER;

    @Override
    public void stateChanged(State<BookStates, BookEvents> from, State<BookStates, BookEvents> to) {
        LOGGER.info("State changed from {} to {}", getStateInfo(from), getStateInfo(to));
    }

    @Override
    public void stateEntered(State<BookStates, BookEvents> state) {
        LOGGER.info("Entered state {}", getStateInfo(state));
    }

    @Override
    public void stateExited(State<BookStates, BookEvents> state) {
        LOGGER.info("Exited state {}", getStateInfo(state));
    }

    @Override
    public void stateMachineStarted(StateMachine<BookStates, BookEvents> stateMachine) {
        LOGGER.info("Machine started: {}", stateMachine);
    }

    @Override
    public void stateMachineStopped(StateMachine<BookStates, BookEvents> stateMachine) {
        LOGGER.info("Machine stopped: {}", stateMachine);
    }

    @Override
    public void stateMachineError(StateMachine<BookStates, BookEvents> stateMachine, Exception exception) {
        LOGGER.error("Machine error: {}", stateMachine);
    }

    @Override
    public void extendedStateChanged(Object key, Object value) {
        LOGGER.info("Extended state changed: [{}: {}]", key, value);
    }

......
}

бегун

@Component
public class RunnerStateMachineWithCommandLine implements CommandLineRunner {

    private final StateMachine<BookStates, BookEvents> stateMachine;

    @Autowired
    public RunnerStateMachineWithCommandLine(StateMachine<BookStates, BookEvents> stateMachine) {
        this.stateMachine = stateMachine;
    }

    @Override
    public void run(String... args){
        stateMachine.start();
        stateMachine.sendEvent(BookEvents.RETURN);
        stateMachine.sendEvent(BookEvents.BORROW);
        stateMachine.stop();
    }
}

Я предложил решение. Это работает. Но зачем мне явно определять общедоступный конечный автомат @Bean? Может быть, кто-нибудь знает, почему это произошло?

skyho 30.11.2020 15:55

Есть много примеров, когда этот подход не используется, но достаточно аннотации @EnableStateMachine.

skyho 30.11.2020 16:01

В классе конфигурации вы можете добавить аннотацию @EnableStateMachineFactory, и она будет работать,

@EnableStateMachineFactory
@Configuration
@Log
public class EmployeeStateMachineConfig extends StateMachineConfigurerAdapter<EmployeeStates, EmployeeEvents> {


}

Другие вопросы по теме