멀티 모듈 아키텍처를 적용한 프로젝트에서 각 모듈 간의 통신을 위해 Spring의 WebClient를 사용하는 것은 비동기적이고 논블로킹 방식으로 서비스 간 통신을 가능하게 하여, 시스템의 전체적인 반응성과 성능을 개선합니다. 이러한 접근 방식은 특히 마이크로서비스 아키텍처(MSA)에서 선호되며, 각 서비스가 독립적으로 개발 및 배포될 수 있도록 지원합니다.
Newsfeed 모듈과 Activity 모듈
Newsfeed 모듈과 Activity 모듈은 사용자의 활동(예: 게시물 생성, 댓글 달기, 좋아요 클릭)과 관련된 데이터를 관리하고, 이를 바탕으로 사용자의 뉴스피드를 생성합니다. 두 모듈 간의 통신은 내부 API를 통해 이루어지며, WebClient를 사용하여 구현합니다.
Newsfeed 모듈
Activity 모듈
SecurityConfig의 업데이트
각 모듈의 SecurityConfig에는 내부 통신을 위한 API 경로(/api/internal/**)를 인증 없이 접근할 수 있도록 설정합니다. 이는 서비스 내부에서의 상호작용을 원활하게 하며, 보안 문제를 방지합니다.
.antMatchers("/api/auth/join",
"/api/auth/login",
"/swagger-ui/**",
"/swagger-resources/**",
"/v3/api-docs/**",
"/api/internal/**") // 추가
.permitAll() // 인증 필요 없는 URL 설정
NewsFeedRestApiController와 PostRestApiController
NewsFeedRestApiController와 PostRestApiController는 내부 API를 통해 다른 모듈들과의 통신을 처리합니다. 예를 들어, 특정 사용자의 모든 알림을 삭제하거나, 특정 사용자의 게시물을 조회하는 등의 기능을 제공합니다.
NewsFeedRestApiController
@RestController
@RequestMapping("/api/internal/feeds")
@RequiredArgsConstructor
public class NewsFeedRestApiController {
private final NewsFeedService newsFeedService;
@DeleteMapping("/user/{userId}")
public ResponseEntity<?> deleteNewsfeedByUserId(@PathVariable Long userId) {
// 사용자 ID를 기반으로 게시물 삭제
newsFeedService.deleteNewsfeedByUserId(userId);
return ResponseEntity.ok().build();
}
@PostMapping("/notis")
public ResponseEntity<?> createNotification(@RequestBody NotificationCreateRequest request) {
newsFeedService.createNotification(request);
return ResponseEntity.ok().build();
}
@DeleteMapping("/notis/type/{typeId}")
public ResponseEntity<?> deleteNotificationByTypeId(@PathVariable Long typeId) {
newsFeedService.deleteNotificationByTypeId(typeId);
return ResponseEntity.ok().build();
}
@DeleteMapping("/notis/post/{postId}")
public ResponseEntity<?> deleteNotificationByPostId(@PathVariable Long postId) {
newsFeedService.deleteNotificationByPostId(postId);
return ResponseEntity.ok().build();
}
}
NewsFeedService
// RestApi
@Transactional
public void deleteNewsfeedByUserId(Long userId) {
notificationRepository.deleteAllByToUserId(userId);
notificationRepository.deleteAllByFromUserId(userId);
followRepository.deleteAllByFollowerId(userId);
followRepository.deleteAllByFollowingId(userId);
}
@Transactional
public void createNotification(NotificationCreateRequest request) {
notificationRepository.mSave(request.getFromUserId(), request.getToUserId(),
request.getType(), request.getPostId(), request.getTypeId());
}
@Transactional
public void deleteNotificationByTypeId(Long typeId) {
notificationRepository.deleteAllByTypeId(typeId);
}
@Transactional
public void deleteNotificationByPostId(Long postId) {
notificationRepository.deleteAllByPostId(postId);
}
PostRestApiController
@RestController
@RequestMapping("/api/internal/posts")
@RequiredArgsConstructor
public class PostRestApiController {
private final PostService postService;
@DeleteMapping("/user/{userId}")
public void deletePostsByUserId(@PathVariable Long userId) {
postService.deleteAllByUserId(userId);
}
@PostMapping("/users")
public List<PostResponseDto> getPostsByUserIds(@RequestBody List<Long> userIds) {
return postService.getPostsByUserIds(userIds);
}
}
WebClient를 활용한 REST API 통신
WebClient를 사용하여 다른 모듈의 REST API를 호출합니다. 이는 비동기적인 방식으로 서비스 간 통신을 가능하게 하며, 시스템의 전체적인 반응성을 향상시킵니다. 예를 들어, 게시물이 삭제될 때 관련된 모든 알림을 삭제하는 요청을 Newsfeed 모듈의 NewsFeedService에서 Activity 모듈로 보낼 수 있습니다.
webClient.delete()
.uri("http://localhost:8081/api/internal/feeds/notis/post/" + postId)
.retrieve()
.bodyToMono(Void.class)
.block();
webClient.delete()
.uri("http://localhost:8081/api/internal/feeds/notis/type/" + like.getId())
.retrieve()
.bodyToMono(Void.class)
.block();
webClient.delete()
.uri("http://localhost:8081/api/internal/feeds/notis/type/" + commentId)
.retrieve()
.bodyToMono(Void.class)
.block();
webClient.post()
.uri("http://localhost:8081/api/internal/feeds/notis")
.bodyValue(request)
.retrieve()
.toBodilessEntity()
.block();
결론
이러한 방식으로, 각 모듈은 독립적으로 배포 및 운영될 수 있으며, WebClient를 사용한 REST API 통신을 통해 간결하고 유연한 서비스 간 상호작용을 구현할 수 있습니다. 이는 마이크로서비스 아키텍처(MSA)의 주요 장점 중 하나로, 개별 서비스의 개발, 배포, 확장이 용이해집니다.
'프로젝트 (Java) > 예약마켓' 카테고리의 다른 글
[프로젝트] 40. Eureka Server 추가 (0) | 2024.02.13 |
---|---|
[프로젝트] 39. 트러블 슈팅 - Rest API 응답 데이터의 Null 값 문제 해결 (0) | 2024.02.06 |
[프로젝트] 37. MSA(MicroService Architecture) 도입 (0) | 2024.02.02 |
[프로젝트] 36. 트러블 슈팅 - Redis와 JWT 토큰 만료 시간 동기화 문제 (0) | 2024.01.31 |
[프로젝트] 35. Swagger 추가 (0) | 2024.01.31 |