ApplicationEvent和ApplicationListener的使用(事件发布和责任链模式)

spring的事件(ApplicationEvent)为bean和bean之间的消息通信提供了支持。当bean处理完一个事件之后,希望另一个bean能够知道并做相应的处理。这时另一个bean监听当前bean所发送的事件。
spring的事件流程如下:

  1. 自己的event需要继承 ApplicationEvent,并且写相应的构造函数
  2. 定义一个监听器listener,实现ApplicationListener接口,重写onApplicationEvent方法
  3. 使用ApplicationContext容器发布事件

案例(伴有责任链模式设计)

创建一个DemoEvent

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.MsgListenerEnum;
import com.lyj.demo.pojo.Student;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.context.ApplicationEvent;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 凌兮
 * @date 2020/4/27 9:02
 * 事件
 */
public class ListenerMsgPutEvent extends ApplicationEvent {
    
    

    private Map<MsgListenerEnum,Object> msgListenerEnums;

    private Long id;

    private Student student;

    public ListenerMsgPutEvent(Object source, Long id, Student student) {
    
    
        super(source);
        this.id = id;
        this.student = student;
    }

    public Map<MsgListenerEnum, Object> getMsgListenerEnums() {
    
    
        return msgListenerEnums;
    }

    public void setMsgListenerEnums(Map<MsgListenerEnum, Object> msgListenerEnums) {
    
    
        this.msgListenerEnums = msgListenerEnums;
    }

    public Long getId() {
    
    
        return id;
    }

    public void setId(Long id) {
    
    
        this.id = id;
    }

    public Student getStudent() {
    
    
        return student;
    }

    public void setStudent(Student student) {
    
    
        this.student = student;
    }

    @Override
    public String toString(){
    
    
        return ToStringBuilder.reflectionToString(this);
    }

//
//    public static void main(String[] args) {
    
    
//        ListenerMsgPutEvent listenerMsgPutEvent = new ListenerMsgPutEvent(null,null,null,null);
//        Map<MsgListenerEnum, Object> msgListenerEnumObjectMap = new HashMap<>();
//        msgListenerEnumObjectMap.put(MsgListenerEnum.SUBMIT_RETURN_ORDER_REMARK,null);
//        Student student = Student.builder()
//                .id(1L)
//                .age(22)
//                .birth(new Date())
//                .build();
//
//        listenerMsgPutEvent.setMsgListenerEnums(msgListenerEnumObjectMap);
//        listenerMsgPutEvent.setId(1L);
//        listenerMsgPutEvent.setStudent(student);
//        System.out.println(listenerMsgPutEvent.toString());
//
//
//    }
}

创建事件监听者

package com.lyj.demo.listener;

import com.lyj.demo.mapper.StudentMapper;
import com.lyj.demo.pojo.Student;
import com.lyj.demo.service.pushMsg.ListenerMsgPutEvent;
import com.lyj.demo.service.pushMsg.MsgPutStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author 凌兮
 * @date 2020/4/27 9:32
 * 事件监听器
 */
@Component
@Slf4j
public class MsgHandlerListener implements ApplicationListener<ListenerMsgPutEvent> {
    
    

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private List<MsgPutStrategy> msgPutStrategies;

    /**
     * 对监听到的事件进行处理
     * @param listenerMsgPutEvent
     */
    @Override
    public void onApplicationEvent(ListenerMsgPutEvent listenerMsgPutEvent) {
    
    
        Long id = listenerMsgPutEvent.getId();
        Student student = studentMapper.selectById(id);
        for (MsgPutStrategy msgPutStrategy :msgPutStrategies) {
    
    
            try {
    
    
                if (msgPutStrategy.choose(listenerMsgPutEvent.getMsgListenerEnums().keySet())){
    
    
                    msgPutStrategy.execute(listenerMsgPutEvent);
                }
            }catch (Exception e){
    
    
                log.error("执行任务失败",e);
            }

        }

    }
}

事件发布

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.MsgListenerEnum;
import com.lyj.demo.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Map;

/**
 * @author 凌兮
 * @date 2020/4/27 10:04
 * 事件发布
 */
@Service
public class MsgPutPublishServiceImpl {
    
    

    /**
     * 注入上下文对象(容器)
     */
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 配置事务,在spring事务提交之后进行异步操作,这些异步操作必须在
     * 事务成功提交后才执行,回滚则不执行这些操作。
     * @param id
     * @param student
     * @param msgListenerEnums
     */
    @Transactional(rollbackFor = Exception.class)
    public void publish(Long id, Student student, Map<MsgListenerEnum,Object> msgListenerEnums){
    
    
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    
    
            @Override
            public void afterCommit() {
    
    
                ListenerMsgPutEvent listenerMsgPutEvent = new ListenerMsgPutEvent(this, id, student);
                listenerMsgPutEvent.setMsgListenerEnums(msgListenerEnums);
                //发布事件
                applicationContext.publishEvent(listenerMsgPutEvent);
            }
        });
    }

}

责任链扩展接口

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.MsgListenerEnum;

import java.util.Set;

/**
 * @author 凌兮
 * @date 2020/4/27 9:35
 */
public interface MsgPutStrategy {
    
    

    /**
     * 是否选择此轨道
     * @param msgListeners
     * @return
     */
    boolean choose(Set<MsgListenerEnum> msgListeners);

    /**
     * 执行监听事件
     * @param listenerMsgPutEvent
     */
    void execute(ListenerMsgPutEvent listenerMsgPutEvent);
}

执行策略1

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.EnumConstant;
import com.lyj.demo.constant.MsgListenerEnum;
import com.lyj.demo.pojo.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Set;

/**
 * @author 凌兮
 * @date 2020/4/27 11:06
 *增加学生信息事件处理
 */
@Service
@Slf4j
public class SubmitStudentStrategy extends AbstractMsgPutEvent {
    
    
    /**
     * 这个文件可以配置rabbitmq推送消息
     * 这里只是模拟事件监听
     * @param msgListeners
     * @return
     */

    @Override
    public boolean choose(Set<MsgListenerEnum> msgListeners) {
    
    
        return msgListeners.contains(MsgListenerEnum.SUBMIT_STUDENT_INFORMATION);
    }

    @Override
    public void execute(ListenerMsgPutEvent listenerMsgPutEvent) {
    
    
        Student student = listenerMsgPutEvent.getStudent();
        try {
    
    
            System.out.println(student.toString());
        } catch (Exception e) {
    
    
            log.error("SubmitStudentStategy error :{}",e);
            saveFailMsg(EnumConstant.BusinessTypeEnums.INSERT_RECORD,student,String.valueOf(student.getId()));
        }
    }


}

执行策略二

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.EnumConstant;
import com.lyj.demo.constant.MsgListenerEnum;
import com.lyj.demo.pojo.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Set;

/**
 * @author 凌兮
 * @date 2020/4/27 11:30
 * 修改学生信息事件处理
 */
@Service
@Slf4j
public class UpdateStudentStategy extends AbstractMsgPutEvent {
    
    
    @Override
    public boolean choose(Set<MsgListenerEnum> msgListeners) {
    
    
        return msgListeners.contains(MsgListenerEnum.UPDATE_STUDENT_INFOREMATION);
    }

    @Override
    public void execute(ListenerMsgPutEvent listenerMsgPutEvent) {
    
    
        Student student = listenerMsgPutEvent.getStudent();
        try {
    
    
            System.out.println(student.toString());
        } catch (Exception e) {
    
    
            log.error("updateStudentStategy error : {}",e);
            saveFailMsg(EnumConstant.BusinessTypeEnums.UPDATE_RECORD,student,String.valueOf(student.getId()));
        }

    }
}

事件发布失败保存落库,后续采用定时任务扫描

package com.lyj.demo.service.pushMsg;

import com.lyj.demo.constant.EnumConstant;
import com.lyj.demo.service.NotificationLogService;
import com.lyj.demo.utils.JacksonUtil;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author 凌兮
 * @date 2020/4/27 10:36
 * 抽象基类
 */
public abstract class AbstractMsgPutEvent implements MsgPutStrategy{
    
    

    @Autowired
    private NotificationLogService notificationLogService;

    protected void saveFailMsg(EnumConstant.BusinessTypeEnums businessTypeEnum,Object content,String businessId) {
    
    
        if (content == null){
    
    
            return;
        }
        notificationLogService.saveNotificationLog(businessTypeEnum,JacksonUtil.toJson(content),
                EnumConstant.NotificationLogState.FAIL.getCode(),businessId);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40093255/article/details/113684659