Skip to content

Commit d7abda7

Browse files
committed
♻️ refactor: 회원 탈퇴 로직에 Observer 패턴 적용하여 서비스 간 결합도 완화
[문제] - 기존의 회원 탈퇴(`withdraw`) 로직은 MemberService가 GroupCommandService, ScheduleCommandService 들을 직접 호출하는 구조 - 서비스 간의 의존성이 높아져 코드의 유연성과 확장성이 저하되는 문제 발생 [접근] Spring의 ApplicationEventPublisher를 사용하여 Observer 패턴을 적용 [변경 사항] - MemberWithdrawalEvent: 회원 탈퇴 시 발행할 이벤트를 정의 - MemberService: ApplicationEventPublisher를 주입받아, 회원 탈퇴가 발생하면 MemberWithdrawalEvent를 발행하도록 withdraw 메서드를 변경, GroupCommandService와 ScheduleCommandService에 대한 직접적인 의존성을 제거 - Group/ScheduleCommandService: @eventlistener 어노테이션을 사용하여 MemberWithdrawalEvent를 구독하는 메서드를 각 서비스에 추가, 각 서비스는 회원 탈퇴 이벤트를 감지하여 그룹 탈퇴 처리, 일정 관리자 위임 등 관련된 후속 작업을 독립적으로 수행 향후 회원 탈퇴 시 추가적인 작업이 필요할 경우 다른 서비스 코드의 수정 없이 새로운 리스너를 추가하는 것만으로 간단하게 확장할 수 있음
1 parent 5aba692 commit d7abda7

File tree

4 files changed

+45
-8
lines changed

4 files changed

+45
-8
lines changed

src/main/java/com/grepp/spring/app/model/group/service/GroupCommandService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.grepp.spring.app.model.group.repository.GroupMemberCommandRepository;
1818
import com.grepp.spring.app.model.group.repository.GroupMemberRepository;
1919
import com.grepp.spring.app.model.member.entity.Member;
20+
import com.grepp.spring.app.model.member.event.MemberWithdrawalEvent;
2021
import com.grepp.spring.app.model.member.repository.MemberRepository;
2122
import com.grepp.spring.app.model.schedule.code.ScheduleRole;
2223
import com.grepp.spring.app.model.schedule.entity.Schedule;
@@ -38,6 +39,7 @@
3839
import java.util.Optional;
3940
import lombok.RequiredArgsConstructor;
4041
import lombok.extern.slf4j.Slf4j;
42+
import org.springframework.context.event.EventListener;
4143
import org.springframework.security.core.Authentication;
4244
import org.springframework.security.core.context.SecurityContextHolder;
4345
import org.springframework.stereotype.Service;
@@ -432,6 +434,14 @@ private void findScheduleMembersOrThrow(ScheduleToGroupRequest request) {
432434
}
433435
}
434436

437+
// 회원 탈퇴 이벤트 리스너
438+
@EventListener
439+
@Transactional
440+
public void handleMemberWithdrawal(MemberWithdrawalEvent event) {
441+
Member member = event.getMember();
442+
handleGroupWithdrawal(member);
443+
}
444+
435445
// 회원 탈퇴 중 그룹 관련 처리 메서드
436446
@Transactional
437447
public void handleGroupWithdrawal(Member member) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.grepp.spring.app.model.member.event;
2+
3+
import com.grepp.spring.app.model.member.entity.Member;
4+
import lombok.Getter;
5+
import org.springframework.context.ApplicationEvent;
6+
7+
@Getter
8+
public class MemberWithdrawalEvent extends ApplicationEvent {
9+
10+
private final Member member;
11+
12+
public MemberWithdrawalEvent(Object source, Member member) {
13+
super(source);
14+
this.member = member;
15+
}
16+
}

src/main/java/com/grepp/spring/app/model/member/service/MemberService.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.grepp.spring.app.controller.api.member.payload.ModifyMemberInfoResponse;
66
import com.grepp.spring.app.model.group.service.GroupCommandService;
77
import com.grepp.spring.app.model.member.entity.Member;
8+
import com.grepp.spring.app.model.member.event.MemberWithdrawalEvent;
89
import com.grepp.spring.app.model.member.repository.MemberRepository;
910
import com.grepp.spring.app.model.schedule.service.ScheduleCommandService;
1011
import com.grepp.spring.infra.error.exceptions.mypage.MemberNotFoundException;
@@ -14,6 +15,7 @@
1415
import java.util.Optional;
1516
import lombok.RequiredArgsConstructor;
1617
import lombok.extern.slf4j.Slf4j;
18+
import org.springframework.context.ApplicationEventPublisher;
1719
import org.springframework.security.core.context.SecurityContextHolder;
1820
import org.springframework.stereotype.Service;
1921
import org.springframework.transaction.annotation.Transactional;
@@ -25,8 +27,7 @@ public class MemberService {
2527

2628
private final MemberRepository memberRepository;
2729
private final AuthService authService;
28-
private final GroupCommandService groupCommandService;
29-
private final ScheduleCommandService scheduleCommandService;
30+
private final ApplicationEventPublisher eventPublisher;
3031

3132
public Optional<Member> findById(String userId) {
3233
return memberRepository.findById(userId);
@@ -75,14 +76,14 @@ public ModifyMemberInfoResponse modifyProfileImage(String userId) {
7576
public void withdraw(String userId, HttpServletResponse response, HttpServletRequest request) {
7677
Member member = memberRepository.findById(userId)
7778
.orElseThrow(() -> new MemberNotFoundException(MyPageErrorCode.MEMBER_NOT_FOUND));
78-
// 1. 그룹 관련
79-
groupCommandService.handleGroupWithdrawal(member);
80-
// 2. 일정 관련
81-
scheduleCommandService.handleScheduleWithdrawal(member);
82-
// 3. 회원 탈퇴(삭제)
79+
80+
// 1. 회원 탈퇴 이벤트 발행
81+
eventPublisher.publishEvent(new MemberWithdrawalEvent(this, member));
82+
83+
// 2. 회원 탈퇴(삭제)
8384
memberRepository.delete(member);
8485
log.info("회원 탈퇴가 완료되었습니다. 회원 ID: {}, 회원명: {}", member.getId(), member.getName());
85-
// 4. 로그아웃 (토큰 무효화)
86+
// 3. 로그아웃 (토큰 무효화)
8687
authService.logout(request, response); // 다른 서비스 참조. 괜찮은가 ?
8788
SecurityContextHolder.clearContext();
8889
}

src/main/java/com/grepp/spring/app/model/schedule/service/ScheduleCommandService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.grepp.spring.app.controller.api.schedule.payload.response.CreateSchedulesResponse;
99
import com.grepp.spring.app.model.event.entity.Event;
1010
import com.grepp.spring.app.model.member.entity.Member;
11+
import com.grepp.spring.app.model.member.event.MemberWithdrawalEvent;
1112
import com.grepp.spring.app.model.member.repository.MemberRepository;
1213
import com.grepp.spring.app.model.schedule.code.MeetingPlatform;
1314
import com.grepp.spring.app.model.schedule.code.ScheduleRole;
@@ -29,6 +30,7 @@
2930
import lombok.extern.slf4j.Slf4j;
3031
import org.springframework.beans.factory.annotation.Autowired;
3132
import org.springframework.beans.factory.annotation.Value;
33+
import org.springframework.context.event.EventListener;
3234
import org.springframework.http.*;
3335
import org.springframework.stereotype.Service;
3436
import org.springframework.transaction.annotation.Transactional;
@@ -555,6 +557,14 @@ private Location saveSuggestedLocation(Schedule schedule, WriteSuggestedLocation
555557
return location;
556558
}
557559

560+
// 회원 탈퇴 이벤트 리스너
561+
@EventListener
562+
@Transactional
563+
public void handleMemberWithdrawal(MemberWithdrawalEvent event) {
564+
Member member = event.getMember();
565+
handleScheduleWithdrawal(member);
566+
}
567+
558568
// 회원 탈퇴 중 일정 관련 처리 메서드
559569
@Transactional
560570
public void handleScheduleWithdrawal(Member member) {

0 commit comments

Comments
 (0)