Spring для событийно-ориентированного программирования

Spring Boot

Когда дело доходит до управляемой событиями модели Spring, я думаю, что все знакомы с ней. Обычно модель, управляемую событиями, можно назвать шаблоном проектирования наблюдателя. Друзья, которые не знакомы с шаблоном проектирования наблюдателя, могут прочитать примечания, которые я писал раньше.Шаблон проектирования Реализация шаблона наблюдателя на языке Java, Что касается управляемой событиями поддержки java, друзья EventBus, которые занимаются разработкой мобильных терминалов, должны знать лучше. На самом деле, сама java также поставляется с поддержкой, управляемой событиями, но большинство из них используются для нашей клиентской разработки, такой как GUI, Swing эти и Spring на базе java, расширенная поддержка событийно-управляемых.

Не говорите ерунды, сразу переходите к коду

1. Кодовый бой

Во-первых, мы создаем новый класс NotifyEvent, который наследует ApplicationEvent, чтобы инкапсулировать дополнительную информацию о нашем событии.Вот сообщение типа String, которое используется для записи подробного содержимого события.

public class NotifyEvent extends ApplicationEvent {

    private String msg;

    public NotifyEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}

Среди них ApplicationEvent — это абстрактный класс, который расширяет класс EventObject самой Java, и каждый подкласс, который наследует ApplicationEvent, представляет класс событий, которые могут передавать данные.

Затем создайте новый NotifyPublisher для нашей работы по публикации событий. Этот класс реализует ApplicationContextAware и переписывает метод setApplicationContext. Целью этого шага является получение нашего контекста приложения Spring, поскольку для публикации событий требуется контекст приложения, а не учащиеся, которые понимают контекст приложения может перейти к другой моей заметке:Что такое контекст?

@Component //声明成组件,为了后期注入方便
public class NotifyPublisher implements ApplicationContextAware {

    private ApplicationContext ctx; //应用上下文

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx= applicationContext;
    }

    // 发布一个消息,这里大家可以根据不同的状态实现发布不同的事件,我这里就只写了一个事件类,所以if else
    //都发布NotifyEvent事件。
    public void publishEvent(int status, String msg) {
        if (status == 0) {
            ctx.publishEvent(new NotifyEvent(this, msg));
        } else {
            ctx.publishEvent(new NotifyEvent(this,msg)) ;
        }
    }
}

Последним шагом является реализация класса в качестве подписчика события.Когда событие будет опубликовано, подписчик будет уведомлен, а затем подписчик будет выполнять соответствующую обработку, такую ​​как автоматическая отправка приветственных писем, когда новые пользователи регистрируются для отправки события и тд. В то же время EventListener, обновленный в Spring 4.2, может легко помочь нам связать события и методы, просто добавьте EventListener в целевой метод.

@Component
public class NotifyListener {

    @EventListener
    //参数NotifyEvent ,当有NotifyEvent 类型的事件发生时,交给sayHello方法处理
    public void sayHello(NotifyEvent notifyEvent){
       System.out.println("收到事件:"+notifyEvent.getMsg());
    }

}

**Тест:** Напишите наш тестовый класс TestController.

@RestController
public class TestController {

    @Autowired
    private NotifyPublisher notifyPublisher;

    @GetMapping("/sayHello")
    public String sayHello(){
        notifyPublisher.publishEvent(1, "我发布了一个事件");
        return "Hello Word";

    }

}


Запускаем наше приложение, в браузере вводим http://127.0.0.1:8080/sayHello, вывод в консоль:

2019-09-28 16:55:51.902  INFO 716 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 12 ms
收到事件:我发布了一个事件

Нарисуйте точку знаний:

Если новое событие наследует NotifyEvent, когда мы отправляем событие типа NotifyEvent, как NotifyEvent, так и слушатели его подкласса могут получить это событие.

Это конец? Пока нет. Помимо того, что я слышу о программировании, управляемом событиями, я иногда вижу слова асинхронное программирование, управляемое событиями. Тот же Spring также предоставляет аннотацию @Async для использования асинхронных событий. Его также очень просто использовать, просто добавьте @Async в @EventListener.

2. Реализация асинхронного события Spring:

код показывает, как показано ниже:

@Component
public class NotifyListener {

    @Async
    @EventListener
    public void sayHello(NotifyEvent notifyEvent){
       System.out.println("收到事件:"+notifyEvent.getMsg());
    }

}

Наконец настройте пул потоков

@Configuration
@EnableAsync
public class AysncListenerConfig implements AsyncConfigurer {
   
    /**
     * 获取异步线程池执行对象
     *
     * @return
     */
    @Override
    @Bean(name = "taskExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.initialize();
        executor.setCorePoolSize(10); //核心线程数
        executor.setMaxPoolSize(20);  //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("ics-Executor-"); ////指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        return new ExceptionHandlingAsyncTaskExecutor(executor);
    }
    
    

}
public class ExceptionHandlingAsyncTaskExecutor implements AsyncTaskExecutor {

    private AsyncTaskExecutor executor;

    public ExceptionHandlingAsyncTaskExecutor(AsyncTaskExecutor executor) {
        this.executor = executor;
    }

    //用独立的线程来包装,@Async其本质就是如此
    public void execute(Runnable task) {
        executor.execute(createWrappedRunnable(task));
    }
    
    public void execute(Runnable task, long startTimeout) {
        //用独立的线程来包装,@Async其本质就是如此
                executor.execute(createWrappedRunnable(task), startTimeout);
    }
    
    
    public Future submit(Runnable task) { return executor.submit(createWrappedRunnable(task));
        //用独立的线程来包装,@Async其本质就是如此。
    }
    
    
    public Future submit(final Callable task) {
        //用独立的线程来包装,@Async其本质就是如此。
        return executor.submit(createCallable(task));
    }

    
    private Callable createCallable(final Callable task) {
        return new Callable(){

            @Override
            public Object call() throws Exception {
                try {
                    return task.call();
                } catch (Exception ex) {
                    handle(ex);
                    throw ex;
                }
            }
        };
    }

   
    private Runnable createWrappedRunnable(final Runnable task) {
        return new Runnable() {
            public void run() {
                try {
                    task.run();
                } catch (Exception ex) {
                    handle(ex);
                }
            }
        };
    }
    private void handle(Exception ex) {
        //具体的异常逻辑处理的地方
        System.err.println("Error during @Async execution: " + ex);
    }
}

контрольная работа: Напишите наш тестовый класс TestController.

2019-09-28 16:55:51.902  INFO 716 --- [on(4)-127.0.0.1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 12 ms
收到事件:我发布了一个事件

Готово.

Электронные заметки и коды выложены на github с открытым исходным кодом (звездочки приветствуются):

GitHub.com/Хан Шуайкан…