기존에는 알림을 전송하는 코드가
public class BoardService {
//모임글 등록
public Board createBoard(BoardDto.Post postDto) {
Member member = findMember(extractMemberId());
Board board = processCreateBoard(postDto, member);
saveApplicantForBoardCreat(board, member);
System.out.println("[모임글 생성에 들어가는 날짜]"+ postDto.getDate());
//알림 발송
alarmService.sendAlarm(member,board, Alarm.AlarmStatus.BOARD_CREATED,"["+board.getTitle()+"] 모임이 등록되었습니다!🔥");
return boardRepository.save(board);
}
}
이런식으로 모임글 작성이 완료되면 작성자에게 알림 전송해야한다? -> 모임글 작성하는 메서드에 바로 추가.
이렇게 작성한다하면, 내가 생각했을때 문제가 2개가 있다.
단일 책임 원칙이 지켜지지 않는다.
모임 글 등록이면 등록만 해야하는데, 알림까지 보내는 기능을 하고있다.
db에 저장되기 전에 알림을 보내고 있기 때문에 알림 기능을 비동기 처리하면 db에 board 정보가 없어서 오류가 발생한다.
알림을 비동기처리하지 않으면, 만약 1번 모임에 참여하는 사람이 5만명이라 가정하면 5만명에게 다 알림을 보내고 마감이든 참여처리를 하게되므로 처리가 엄청나게 지연된다.
그렇게때문에 비동기 처리가 필요하고, 비동기 처리를 하려면 기존 글 생성 로직이 수정이 필요했다.
계속 모임글 생성 메서드로 예를 들면,
public class BoardService {
//모임글 등록
public Board createBoard(BoardDto.Post postDto) {
Member member = findMember(extractMemberId());
Board board = processCreateBoard(postDto, member);
saveApplicantForBoardCreat(board, member);
//작성한 모임 저장
Board savedBoard = boardRepository.save(board);
//알림 발송
notifyCreateBoard(member, board);
return savedBoard;
}
.
.
.
//모임글 작성 시 알림 전송 (알림 발송 관련 메서드)
private void notifyCreateBoard (Member member, Board board){
alarmService.sendBoardCreatedNotification(member,board);
}
//날짜 지난 모임 마감 알림 전송 (알림 발송 관련 메서드)
private void notifyDeadline (Board board){
alarmService.sendCompletedNotification(board);
}
이렇게 분리를하고, 글이 저장되면 -> 알림 service class에 전달
public class AlarmService {
/**
* 알림 생성, 전송 메서드
* 사용자의 모든 알람을 읽음처리
*/
@Async
public void sendAlarm(Member member, Board board, Alarm.AlarmStatus alarmStatus, String content){
Alarm alarm = Alarm.create(member, board, alarmStatus,content);
alarmRepository.save(alarm);
Map<String, SseEmitter> sseEmitters = emitterRepository.findAllEmittersStartWithByMemberId(member.getId());
String eventId = makeTimeIncludedId(member.getId());
System.out.println(eventId);
sseEmitters.forEach((key, emitter) -> {
//데이터 캐시 저장 (유실 데이터 처리를 위해)
emitterRepository.saveEventCache(key,alarm);
//데이터 전송
sendToClient(emitter,eventId, content);
});
}
//모임 글 작성자에게 알림 전송
public void sendBoardCreatedNotification(Member member, Board board){
sendAlarm(member,board,Alarm.AlarmStatus.BOARD_CREATED,"["+board.getTitle()+"] 모임이 등록되었습니다!🔥");
}
//모임 참여자 발생 시 참여 중인 모든 인원에게 알림 전송
public void sendParticipantsNotification(Board board){
sendAlarm(board.getMember(), board, Alarm.AlarmStatus.BOARD_UPDATE, "["+board.getTitle()+"] 모임에 새로운 인연이 모임에 찾아왔어요 💝");
}
이렇게 각 전달 받은 것들을 최종 알림 전송 메서드에 전달해서 알림을 생성하도록 변경했다.
사실 이 방법도 서비스간 결합도가 높아지기 때문에 좋은 방법은 아니다.
그래서 좀 더 발전시키면 EventPublisher를 사용하는 방법이 있다.
이벤트를 발행하면 EventListener는 리스닝하고 있다가 발행된 이벤트를 처리해주는 방식이다.
refernce
https://ksh-coding.tistory.com/111
https://ivvve.github.io/2019/06/04/java/Spring/event-listener-3/