Публикация и подписка на события SpringBoot

Spring Boot

В повседневной разработке часто встречается, что один метод завершен, а другой метод нужно уведомить.
Например, после того, как пользователь зарегистрировался, ему необходимо отправить ему электронное письмо. Такой основной бизнес включает в себя множество дочерних предприятий, Если требования к транзакции не очень строгие, вы можете попробовать публикацию событий и подписку SpringBoot.

класс событий

Сначала вам нужно определить событие, этот класс наследуетApplicationEventэтот абстрактный класс.

import org.springframework.context.ApplicationEvent;

/**
 * 定义一个自定义事件,继承ApplicationEvent类
 *
 * @author lww
 * @date 2020-04-09 17:41
 */
public class MyApplicationEvent extends ApplicationEvent {

    private static final long serialVersionUID = 1L;

    public MyApplicationEvent(Object source) {
        super(source);
        System.err.println("发布事件:source = " + source);
    }
}

Опубликовать событие

Публикация событий проста, внедрениеApplicationContext,перечислитьcontext.publishEvent(new MyApplicationEvent("发布事件啦"));Ну такое событие публикуется.

import com.ler.eventdemo.event.MyApplicationEvent;
import javax.annotation.Resource;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lww
 * @date 2020-04-09 18:05
 */
@RestController
public class HelloController {

    @Resource
    private ApplicationContext context;

    @GetMapping("/hello")
    public String hello(String name) {
        context.publishEvent(new MyApplicationEvent("发布事件啦"));
        return "Hello " + name;
    }

}

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

Подписаться на события

Вместе с событием событие публикуется, и следующим шагом является подписка на событие. Тоже очень просто, нужно просто написать слушатель

import com.ler.eventdemo.event.MyApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * 定义一个事件监听器 MyApplicationListener
 *
 * @author lww
 * @date 2020-04-09 17:42
 */
@Component
public class MyApplicationListener {

    @EventListener
    public void onApplicationEvent(MyApplicationEvent event) {
        System.err.println("接收到事件:" + event.getClass());
    }

}

Некоторые говорят, чтоApplicationListenerИнтерфейс, после тестирования установлено, что нет необходимости реализовывать какой-либо интерфейс. просто добавь@EventListenerАннотация, а затем параметр указывает, какое событие, и все.

В событии подписки также есть небольшая иконка, и щелчок по ней приведет к переходу к событию публикации (в идее).

@TransactionalEventListener

@TransactionalEventListenerи@EventListenerодин короткийTransactional, эта транзакция означает, Время отправки событий может быть привязано к транзакциям.

  • TransactionPhase.BEFORE_COMMIT перед фиксацией
  • TransactionPhase.AFTER_COMMIT после фиксации
  • TransactionPhase.AFTER_ROLLBACK после отката
  • TransactionPhase.AFTER_COMPLETION после завершения транзакции

дефолтTransactionPhase.AFTER_COMMIT.

При указании времени выпуска следует избегать ситуации, когда, например, регистрация пользователя включает в себя некоторые трудоемкие операции, и некоторые из этих операций являются асинхронными и неблокирующими. Когда выполняется метод, который публикует событие. Пользователь может быть еще не создан. Если событие опубликовано в это время, оно может не получить пользователя при выполнении на стороне слушателя. И если он выполняется после фиксации транзакции, этого не будет.

эта аннотациянетСкажите, какова транзакционная связь между методом, который публикует событие, и методом ответа слушателя. Между ними по-прежнему нет никаких дел. Атомарность, согласованность не могут быть гарантированы.

Если вы хотите реализовать транзакцию, это возможно.Вы можете сначала убедиться, что издатель событий выполнен и транзакция отправлена. Затем подписчик следует правилу идемпотентности, Если подписчик терпит неудачу, введите механизм повторной попытки. Немного похоже на фиксацию сегмента RocketMQ, возврат транзакций и механизм повторных попыток. Это может быть реализовано в соответствии с этой идеей.

принцип

  • ApplicationContextинтерфейс наследуетApplicationEventPublisherинтерфейс, так что естьpublishEventметод, который можно использовать для публикации задач.
  • ApplicationListenerинтерфейс наследуетEventListenerинтерфейс, который имеетonApplicationEventспособ прослушивания событий.

существуетorg.springframework.context.support.AbstractApplicationContext#refreshметод,org.springframework.context.support.AbstractApplicationContext#registerListenersв

Как видите, поиск осуществляется при регистрации слушателя.ApplicationListenerЕсли мы не реализуем интерфейс, как нам его зарегистрировать?

@EventListenerВ комментарии есть это предложение, посмотрите на этот метод этого классаorg.springframework.context.event.EventListenerMethodProcessor#processBean

Здесь найдите с помощью@EventListenerМетод аннотирования также будет добавлен вConfigurableApplicationContext(ApplicationContextкласс реализации), как слушатель. так не реализованоApplicationListener, также можно использовать в обычном режиме.
Обратите внимание, что вам нужно использовать класс конфигурации Java.Если вы используете конфигурацию xml, вам нужно добавить<context:annotation-config/>или<context:component-scan/>

и@TransactionalEventListenerВключают@EventListener

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener
public @interface TransactionalEventListener {
    ......
}

@TransactionalEventListenerЗависит отorg.springframework.transaction.event.TransactionalEventListenerFactoryиметь дело с, в этом методеorg.springframework.transaction.event.TransactionalEventListenerFactory#createApplicationListenerсозданныйorg.springframework.transaction.event.ApplicationListenerMethodTransactionalAdapter#ApplicationListenerMethodTransactionalAdapterсуществуетorg.springframework.transaction.event.ApplicationListenerMethodTransactionalAdapter#onApplicationEventВ этом методе используйтеTransactionSynchronizationEventAdapterуправлять делами.

Суммировать

Публикация и подписка на события SpringBoot очень проста и удобна в использовании, а также широко используется во фреймворке SpringBoot.Давайте потренируемся быстро, друзья.

В этой статье используетсяmdniceнабор текста