의존 관계가 있다? 스프링 빈이 관리된다?
앞선 포스팅에서 MemberService를 회원 가입 및 조회 로직를 생성하고 MemberRepository에 이를 저장 및 조회하였다.
이제 화면을 그려야 하는데, 이를 위해서는 MemberController와 View Template이 필요하며, MemberController은 MemberService를 통해서 회원 가입을 하고 데이터를 조회할 수 있어야 한다. 이를 바로 "의존 관계가 있다"고 표현한다.
먼저 MemberController라는 java class를 생성하고, @Controller 어노테이션을 붙인다.
package springTest.hellospring.controller;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
}
여기까지 구현하면, 아직 기능은 없지만 Spring을 실행할 때 Spring Container라는 하나의 Bucket이 생성되면서, 여기에 @Controller 어노테이션이 붙은 MemberController를 넣어놓고 관리한다. 이를 "Spring Container에서 Spring Bean이 관리된다"라고 표현한다.
MemberService를 새로 생성하기보다는 하나의 Service를 Container에 등록하고 이를 사용하도록 한다. 앞서 MemberService에서 MemberRepository를 받아오는 것처럼 다음과 같이 MemberService를 받아오도록 구현하고, 생성자 앞에 @Autowired 어노테이션을 설정한다. @Autowired는 Container에서 Service를 가져온다.(스프링 컨테이너에 저장된 빈(객체)을 전달할 때 사용)(Dependency Injection에 사용)
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
실행하면 다음과 같은 에러가 발생한다. MemberService는 순수한 Java Class이기 때문에 Spring이 이 친구를 알 수 있는 방법이 없기 때문이다. 이 문제를 해결하기 위해 @Service 어노테이션을 붙여야한다.
@Service를 붙이면 @Controller와 마찬가지로 Spring이 실행될 때 Container에 등록하게 된다. 마찬가지로 Repository도 구현체에다가 @Repository 어노테이션을 붙인다.
Consider defining a bean of type 'hello.hellospring.service.MemberService' in your configuration.
// MemberService
public class MemberService {
private final MemberRepository memberRepository;
...
}
@Repository
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
...
}
Controller, Service, Repository 연결
앞서 Controller와 Service를 연결하였을 때 @Autowired를 사용했었다. MemberController가 생성될 때 Spring Bean에 등록되어있는 MemberService 객체를 가져다가 넣어준다. 이것이 바로 "Dependency Injection"이라고 한다.
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
MemberService도 마찬가지이다. MemberRepository가 필요하기 때문에 @Autowired 어노테이션을 붙여서 MemberService가 생성될 때 Spring Bean에 등록되어있는 MemberRepository 객체를 가져다가 넣는다.
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
...
}
Spring Bean을 등록하는 방법
# Spring이 Spring Bean을 등록할 때의 특징
Spring은 Spring Container에 Spring Bean을 등록할 때, 기본적으로 싱글톤으로 등록한다. 따라서 같은 Spring Bean이면 모두 같은 인스턴스이다. 물론 설정을 통해 싱글톤이 아니게 설정할 수 있지만, 대부분은 싱글톤을 사용한다.
# Component Scan
앞서 한 @Controller, @Service, @Repository이 컴포넌트 스캔 방식이다. @Controller, @Service, @Repository 모두 @Component이 내장되어 있다.
즉, @Component가 붙어 있으면 Spring Bean으로 Spring 실행 시 Container에 객체를 넣고, @Autowired는 이를 연결하는데 사용된다.
그렇다면 아무 곳에다가 @Component를 붙여도 모두 다 빈에 등록될까? 안된다!
지금 실행하는 Main Class의 springTest.hellospring 패키지를 포함한 하위 패키지들만 다 뒤져서 Spring Bean에 등록한다.
package springTest.hellospring;
...
@SpringBootApplication
public class HelloSpringApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringApplication.class, args);
}
}
# 자동 의존 관계 설정
출처
'🌱 Spring > 회원 관리 예제' 카테고리의 다른 글
[Spring] 통합 테스트 (0) | 2023.07.07 |
---|---|
[Spring] 웹 UI 및 비즈니스 로직(가입, 조회) 연결 (0) | 2023.07.05 |
[Spring] 회원 서비스 테스트(Dependency Injection) (0) | 2023.07.05 |
[Spring] 회원 Service 개발 (0) | 2023.07.03 |
[Spring] 회원 Repository 테스트 케이스 작성(메서드 실행 순서 보장?) (0) | 2023.07.03 |