Невозможно перехватить и обработать пользовательские события весны в java - PullRequest
0 голосов
/ 16 февраля 2020

Я пытаюсь настроить собственное издательство весеннего события и слушателя. Ход процесса, кажется, работает нормально, я могу видеть распечатки до того, как событие публикуется, однако мои слушатели не распознают событие. мой основной класс:

public class TestClass {

        public static void main(String[] args) throws Exception {
            testEvents();
        }

        private static void testEvents() throws InterruptedException {
            AnnotationConfigApplicationContext eventPublisherContext = new AnnotationConfigApplicationContext(EventListenerConfig.class);
            CustomSpringEventPublisher eventPublisher = eventPublisherContext.getBean(CustomSpringEventPublisher.class);
            List<CustomSpringEventListener> listenersList = new ArrayList<CustomSpringEventListener>();

            for (int i = 0; i < 5; i++) {
                listenersList.add(new CustomSpringEventListener("LR" + (i + 1)));
            }

            for (int i = 0; i < 10; i++) {
                Thread.sleep(5000);

                LocalDateTime now  = LocalDateTime.now();
                eventPublisher.doStuffAndPublishAnEvent("new event " + now.format(Formats.isolong));
            }
        }
    }

вот мой класс пользовательских событий:

public class CustomSpringEvent extends ApplicationEvent {
    private String message;

    public CustomSpringEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

}

вот мой класс издателя пользовательских событий:

@Component
public class CustomSpringEventPublisher {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void doStuffAndPublishAnEvent(final String message) {
        System.out.println("Publishing custom event --> " + message);
        this.applicationEventPublisher.publishEvent(new CustomSpringEvent(this, message));
    }

}

вот мой Пользовательский класс прослушивателя событий:

public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    private String name;

    public CustomSpringEventListener(String name) {
        this.name = name;
    }

    @Override
    @EventListener
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println(name + " received spring custom event - " + event.getMessage());
    }

}

Вот мой класс конфигурации прослушивателя событий:

@Configuration
@ComponentScan({"some.local.directory.testCases"})
public class EventListenerConfig {
}

Что мне здесь не хватает? Как я могу заставить свой класс слушателя распознать опубликованное событие и обработать его? Я видел несколько примеров, в которых класс слушателя имеет @Component, но когда я попытался добавить его, я получил ошибку от пружины: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate., также я не вижу никакой причины, почему класс слушателя имел бы эту аннотацию в этот случай. Любая помощь будет оценена. Спасибо.

1 Ответ

1 голос
/ 16 февраля 2020

Чтобы вызвать прослушиватели событий, Spring должен знать класс слушателя и поместить его в applicationContext, что называется Bean .

. Вам нужно аннотировать ваш класс с @Component. Но когда вы делаете это, вы получаете ошибку. Давайте проясним это.

Краткий обзор Spring

Наличие класса, помеченного @Component, будет указывать Spring на то, что ему нужно "управлять" самим классом. Управляя, он включает в себя создание всех «зависимостей», а затем вызов «конструктора». Давайте назовем это деревом зависимостей . Как только Spring достигнет дна, он может начать подниматься и создавать объект и возвращаться к вершине.

Управление зависимостями

Spring знает зависимости вашего класса, анализируя конструктор , сеттер или атрибуты, помеченные @Autowired. Обратите внимание, что если в вашем классе есть только один конструктор, Spring автоматически сканирует его, чтобы узнать о зависимостях, даже если в его верхней части нет @Autowired.

В вашем случае для CustomSpringEventListener у вас есть один конструктор, принимающий параметр String. Если мы построим дерево зависимостей вашего CustomSpringEventListener, мы получим что-то вроде этого:

CustomSpringEventListener ---> String

Так что, когда Spring попытается создать ваш CustomSpringEventListener, он будет искать бин типа String, потому что ваш код говорит: если вы когда-нибудь захотите создать объект CustomSpringEventListener, вам нужно дать имя, которое является строкой. Но в вашем коде нет бина типа String, я думаю.

Решение

Сначала аннотируйте свой класс CustomSpringEventListener с помощью @Component и удалите свой атрибут и конструктор.

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {

    @Override
    @EventListener
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }

}

Во второй раз найдите другой способ иметь имя в вашем классе, если оно вам действительно нужно.

Слушатель с атрибутами

Давайте скажем, вам нужен более сложный слушатель, например, использующий ServiceA. Вы можете сделать следующее:

@Service
public class ServiceA { ... }
@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    private ServiceA serviceA;

    public CustomSpringEventListener(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

}

Тот же слушатель с именем

Вы можете объединить класс @Configuration, чтобы создать много раз одного и того же слушателя. Давайте используем ваш первый Listener с атрибутом name.

public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    private String name;

    public CustomSpringEventListener(String name) {
        this.name = name;
    }

    @Override
    @EventListener
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println(name + " received spring custom event - " + event.getMessage());
    }

}

Без аннотации @Component вы можете использовать класс @Configuration для создания экземпляра Listener:

@Configuration
public ListenerConfig {

    public CustomSpringEventListener listenerA() {
        return new CustomSpringEventListener("listenerA");
    }

    public CustomSpringEventListener listenerB() {
        return new CustomSpringEventListener("listenerB");
    }

    public CustomSpringEventListener listenerC() {
        return new CustomSpringEventListener("listenerC");
    }

    ...
}

Вы можете смешивать конфигурацию Spring с любой необходимой конфигурацией.

Надеюсь, это поможет.

...