본문 바로가기
스프링과 JPA 기반 웹 어플리케이션 개발/7부 알림

72. 알림 처리 설계

by Backchus 2020. 5. 11.

ApplicationEventPublisher와 스프링 @Async 기능을 사용해서 비동기 이벤트 기반으로 알림 처리.

  • 주요 로직 응답 시간에 영향을 주지 않기.
  • 코드를 최대한 주요 로직에 집중하고 알림 처리 로직은 분리.

 

스프링 이벤트 프로그래밍 모델

ApplicationEventPublisher.publishEvent(Event) // 이벤트 발생

@EventListener // 이벤트 처리
public void handlerEvent(Event event)

 

스프링 @Async 기능 설정

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
	// Executor 설정
}

 

ThreadPoolTaskExecutor

  • https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html
  • CorePoolSize, MaxPoolSize, QueueCapacity
  • 처리할 태스크(이벤트)가 생겼을 때,
  • '현재 일하고 있는 쓰레드 개수'(active thread)가 '코어 개수'(core pool size)보다 작으면 남아있는 쓰레드를 사용한다.
  • '현재 일하고 있는 쓰레드 개수'가 코어 개수만큼 차있으면 '큐 용량'(queue capacity)이 찰때까지 큐에 쌓아 둔다.
  • 큐 용량이 다 차면, 코어 개수를 넘어서 '맥스 개수'(max pool size)에 다르기 전까지 새로운 쓰레드를 만들어 처리한다.
  • 맥스 개수를 넘기면 태스크를 처리하지 못한다.

 

비동기 이벤트 로직을 구현하기 전에 비동기 관련 설정 생성

package me.weekbelt.studyolle.infra.config;

@Slf4j
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int processorsNum = Runtime.getRuntime().availableProcessors();
        log.info("processor count {}", processorsNum);
        executor.setCorePoolSize(processorsNum);
        executor.setMaxPoolSize(processorsNum * 2);
        executor.setQueueCapacity(50);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("AsyncExecutor-");
        executor.initialize();
        return executor;
    }
}

 

새로운 스터디를 개설할때 알림이벤트를 발생시키기 위해 ApplicationEventPulisher클래스를 추가해 이벤트를 등록

package me.weekbelt.studyolle.modules.study;


@RequiredArgsConstructor
@Transactional
@Service
public class StudyService {

    // ..........
    
    private final ApplicationEventPublisher eventPublisher;

    public Study createNewStudy(Study study, Account account) {
        Study newStudy = studyRepository.save(study);             
        newStudy.addManager(account);
        eventPublisher.publishEvent(new StudyCreatedEvent(newStudy));  // 이벤트 처리 알림 추가
        return newStudy;
    }

    // .........
}
package me.weekbelt.studyolle.modules.study.event;

@Getter
public class StudyCreatedEvent {

    private Study study;

    public StudyCreatedEvent(Study study) {
        this.study = study;
    }
}

 

해당 이벤트를 처리하는 이벤트 리스너 추가

package me.weekbelt.studyolle.modules.study.event;

@Slf4j
@Async
@Transactional
@Component
public class StudyEventListener {

    @EventListener
    public void handleStudyCreatedEvent(StudyCreatedEvent studyCreatedEvent) {
        Study study = studyCreatedEvent.getStudy();
        log.info(study.getTitle() + "is created.");
        // TODO 이메일 보내거나, DB에 Notification 정보를 저장하면 됩니다.
    }
}

 

 

참고: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1#

 

스프링과 JPA 기반 웹 애플리케이션 개발 - 인프런

이 강좌에서 여러분은 실제로 운영 중인 서비스를 스프링, JPA 그리고 타임리프를 비롯한 여러 자바 기반의 여러 오픈 소스 기술을 사용하여 웹 애플리케이션을 개발하는 과정을 학습할 수 있습�

www.inflearn.com