Spring Events을 활용하여 결합도 낮추기

2024. 12. 23. 22:15·Spring

먼저, 이 글에서는 Spring Events를 활용한 코드 리팩터링을 다룹니다. 하지만 Spring Events가 익숙하지 않은 분들은 아래 링크를 통해 기본 개념을 먼저 확인하시면 이해에 도움이 될 것입니다:

 

➡️ Spring Events란? - Gahacman의 블로그

 

저의 코드는 크롤링중에 새로운 기사가 크롤링 된다면 알림서비스로 새로운 기사가 발행되었다고 알림을 보냅니다.

이후 데이터베이스에 새로운 기사들을 저장합니다.

기존의 코드의 문제점

package com.hnptech.stocknewscuckoo.article.service;

import com.hnptech.stocknewscuckoo.article.dto.response.ArticleResponse;
import com.hnptech.stocknewscuckoo.article.mapper.ArticleMapper;
import com.hnptech.stocknewscuckoo.article.model.Article;
import com.hnptech.stocknewscuckoo.article.repository.ArticleRepository;
import com.hnptech.stocknewscuckoo.notification.notifier.Notifier;
import com.hnptech.stocknewscuckoo.notification.service.NotificationService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ArticleServiceImpl implements ArticleService {

	private final ArticleRepository articleRepository;
	private final ArticleMapper articleMapper;
	private final NotificationService notificationService;
	@Override
	public List<ArticleResponse> getLatestArticles() {
		 return articleMapper.toResponseList(articleRepository.findTop20ByOrderByPublishedAtDesc());
	}

	@Override
	public void saveArticles(List<Article> articles) {
		List<Article> notDuplicatedArticles = articles.stream()
				.filter(article -> !articleRepository.existsById(article.getUrl()))
				.toList();

		// 알림서비스
		for (Article article : notDuplicatedArticles) {
			notificationService.sendNotification(article);
		}

		articleRepository.saveAll(notDuplicatedArticles);
	}

}

 

 

  • 로직의 결합도가 높음
    • saveArticles 메서드 내에 기사 저장 로직과 알림 로직이 함께 포함되어 있어 단일 책임 원칙(SRP)을 위반하고 있습니다.
    • 이로 인해 로직 간의 강한 결합도가 발생하며, 코드의 유지보수성과 확장성이 저하됩니다.
  • 동기 방식으로 인한 성능 문제
    • 알림 전송 로직이 동기적으로 처리되기 때문에, 알림 전송에 시간이 오래 걸릴 경우 saveArticles 메서드 전체가 대기 상태에 들어갑니다.
    • 이는 서비스의 성능 저하로 이어질 수 있습니다.
  • 테스트 작성의 어려움
    • 비즈니스 로직(기사 저장)과 알림 로직이 결합되어 있어, 기사 저장 로직을 테스트하려면 알림 로직까지 모킹(mocking)하거나 테스트 환경을 구성해야 합니다.
    • 이로 인해 단위 테스트 작성이 복잡해지고 테스트의 신뢰성을 확보하기 어렵습니다.

해결 과정

리팩터링: Spring Events 적용

Spring Events를 활용하여 문제를 해결하였습니다. 이벤트 기반 구조로 분리함으로써 각 로직의 결합도를 줄이고 비동기 처리를 통해 성능을 개선하였습니다.

1. 이벤트 클래스 정의

이벤트 데이터를 담을 ArticleCreatedEvent와 CrawlerFetchedEvent 클래스를 작성하였습니다. 

public record ArticleCreatedEvent(List<Article> articles) implements Event {
}

 

2. 이벤트 퍼블리셔 (Publisher) 구현

이벤트를 발행하는 클래스를 작성하여, 비즈니스 로직에서 이벤트 발행을 간단히 수행할 수 있도록 설계했습니다.

@Component
@RequiredArgsConstructor
public class ArticleEventPublisher {
	private final EventPublisher eventPublisher;

	public void publishArticleCreated(List<Article> articles) {
		ArticleCreatedEvent event = new ArticleCreatedEvent(articles);
		eventPublisher.publish(event);
	}
}

3. 이벤트 리스너 (Listener) 구현

리스너를 통해 알림 전송 로직을 분리하고 비동기 방식으로 처리하도록 설정하였습니다.

@Component
@RequiredArgsConstructor
@Slf4j
public class ArticleEventListener {
	private final NotificationService notificationService;

	@Async
	@EventListener
	public void handleArticleCreatedEvent(@NonNull ArticleCreatedEvent event) {
		log.info("알림 보내기 성공");
		notificationService.sendNotification(event);
	}
}

 

최종 리팩토링 코드

@Override
public void saveArticles(CrawlerFetchedEvent articles) {
	// 중복 검사
	List<Article> notDuplicatedArticles = articles.articles().stream()
			.filter(article -> !articleRepository.existsById(article.getUrl()))
			.toList();

	// 이벤트 발행
	articleEventPublisher.publishArticleCreated(notDuplicatedArticles);

	// 데이터 저장
	articleRepository.saveAll(notDuplicatedArticles);
}

 

'Spring' 카테고리의 다른 글

[KAFKA] Spring Boot로 KAFKA 사용해보기  (0) 2025.04.02
[해결 방안] Spring STOMP content-length 초과 에러 해결하기  (0) 2025.03.31
[해결 방안] Spring Gateway를 통해 Stomp를 설정했을때 헤더가 두개오는 문제 해결방안  (1) 2025.03.31
[Spring] MongoDB와 JPA Repository 충돌 해결  (1) 2025.02.09
[Spring] Spring Events 이란?  (5) 2024.12.22
'Spring' 카테고리의 다른 글
  • [해결 방안] Spring STOMP content-length 초과 에러 해결하기
  • [해결 방안] Spring Gateway를 통해 Stomp를 설정했을때 헤더가 두개오는 문제 해결방안
  • [Spring] MongoDB와 JPA Repository 충돌 해결
  • [Spring] Spring Events 이란?
절박한개발자
절박한개발자
깃허브 주소 : https://github.com/Kzerojun
  • 절박한개발자
    절박한개발
    절박한개발자
  • 전체
    오늘
    어제
    • 분류 전체보기 (99)
      • Server (5)
      • 프로젝트 (7)
      • Spring (7)
      • AI (1)
      • JPA (6)
      • JAVA (7)
      • Backend (3)
      • WEB (3)
      • 알고리즘-이론 (6)
      • 알고리즘-문제 (28)
      • CS (24)
        • 데이터베이스 (8)
        • Network (5)
        • OS (10)
        • LINUX (1)
      • 개발면접준비 (1)
      • 기타 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    2
    CPU
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
절박한개발자
Spring Events을 활용하여 결합도 낮추기
상단으로

티스토리툴바