스프링 입문4 (코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술)(feat.김영한 강사님)

권영태·2023년 5월 2일
0

스프링

목록 보기
5/18

Project : Gradle-Groovy Project
JDK : JAVA 17
Spring Boot Version : 3.0.6
Dependencies : Spring Web, Thymeleaf, H2database
IDEA : IntelliJ IDEA

이번 시간에는 서비스부터 컨트롤러 그리고 스프링 빈과 의존관계를 알아보자.

👤 회원 서비스

public class MemberService {
 
 private final MemberRepository memberRepository = 
 new MemoryMemberRepository();
 
 /**
 * 회원가입
 */
 
 public Long join(Member member) {
 	validateDuplicateMember(member); //중복 회원 검증
 	memberRepository.save(member);
 	return member.getId();
 }
 
 private void validateDuplicateMember(Member member) {
 	memberRepository.findByName(member.getName())
 	.ifPresent(m -> {
 	throw new IllegalStateException("이미 존재하는 회원입니다.");
 });
 }
 
 /**
 * 전체 회원 조회
 */
 
 public List<Member> findMembers() {
 	return memberRepository.findAll();
 }
 
 public Optional<Member> findOne(Long memberId) {
 	return memberRepository.findById(memberId);
 }
}

서비스 테스트에 앞서 기존 서비스 코드는 서비스가 메모리 회원 리포지토리를 직접 생성 시켰다.
이를 DI 가능하게 변경하고 넘어간다.

public class MemberService {

/* private final MemberRepository memberRepository =
 new MemoryMemberRepository() 직접 생성 */
 
 private final MemberRepository memberRepository; 
  
 public MemberService(MemberRepository memberRepository) {
 	this.memberRepository = memberRepository;
 }
 ...
}

⚙️ 회원 서비스 테스트

class MemberServiceTest {
 MemberService memberService;
 MemoryMemberRepository memberRepository;
 
 @BeforeEach	// DI
 public void beforeEach() {
 	memberRepository = new MemoryMemberRepository();
 	memberService = new MemberService(memberRepository);
 }
 
 @AfterEach	// 메서드가 끝난 후에 실행
 public void afterEach() {
 	memberRepository.clearStore();
 }
 
 @Test
 public void 회원가입() throws Exception {
 	//Given
 	Member member = new Member();
 	member.setName("hello");
 
 	//When
 	Long saveId = memberService.join(member);
 
 	//Then
 	Member findMember = memberRepository.findById(saveId).get();
 	assertEquals(member.getName(), findMember.getName());
 }

@Test
public void 중복_회원_예외() throws Exception {
 //Given
 Member member1 = new Member();
 member1.setName("spring");
 Member member2 = new Member();
 member2.setName("spring");
 
 //When
 memberService.join(member1);
 IllegalStateException e = assertThrows(IllegalStateException.class,
 () -> memberService.join(member2));//예외가 발생해야 한다.
 assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
 }
}
  • BeforeEach는 각 테스트 실행 전에 호출되는 어노테이션.
    테스트가 서로 영향이 없도록 새로운 객체를 생성하고, 의존관계도 맺어줌

🫘 스프링 빈과 의존관계

  • 회원 컨트롤러가 서비스와 리포지토리를 사용할 수 있게 의존관계 추가

🛠️ 컴포넌트 스캔과 자동 의존관계 설정

@Controller		// 스프링 빈 자동 등록
public class MemberController {
 	private final MemberService memberService;
 
 	// 스프링 컨테이너에 있는 MemeberService와 연결
 	@Autowired
 	public MemberController(MemberService memberService) {
 	this.memberService = memberService;
 }
}

@Service	// 스프링 빈 자동 등록
public class MemberService {
 	private final MemberRepository memberRepository;
 
 	// 스프링 컨테이너에 있는 MemberRepository와 연결
 	@Autowired
 	public MemberService(MemberRepository memberRepository) {
 	this.memberRepository = memberRepository;
 }
}

@Repository		// 스프링 빈 자동 등록
public class MemoryMemberRepository implements MemberRepository {}
  • 생성자에 @Autowired가 붙으면 객체 생성 시점에 스프링 컨테이너에서 연관된 객체를 찾아서 넣어주며 이를 DI라고 한다.
  • 생성자가 1개라면 @Autowired 생략 가능!

스프링 컨테이너에 컨트롤러, 서비스, 리포지토리가 빈으로 등록되어 있다.

📄 자바 코드로 직접 스프링 빈 등록하기

@Configuration
public class SpringConfig {
 
 @Bean		// 반환되는 객체를 빈으로 등록
 public MemberService memberService() {
 	return new MemberService(memberRepository());
 }
 
 @Bean
 public MemberRepository memberRepository() {
	return new MemoryMemberRepository();
 }
}
  • DI 방식으로 필드 주입, setter 주입, 생성자 주입 총 3가지 방식이 존재. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없어 생성자 주입을 권장.
  • @Autowrired를 통한 DI는 스프링이 관리하는 객체에서만 동작하며, 스프링 빈으로 등록하지 않고 직접 생성한 객체에서는 동작하지 않음.
profile
GitHub : https://github.com/dudxo

0개의 댓글