스프링 빈을 등록하는 방법(컴포넌트 스캔/자바 코드로 등록)
생성자 주입
1. 컴포넌트 스캔과 자동 의존관계 설정
1) MemberController
2) MemberService
3) MemberRepository (interface) -> 구현체 MemoryMemberRepository
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
}
- 생성자에 @Autowired를 달아 의존성을 주입해준다. (단, 생성자가 1개만 있으면 @Autowired 생략 가능)
- @Component 애너테이션이 있으면 스프링 빈으로 자동 등록됨.
- @Controller, @Service, @Repository는 @Componenet를 포함하고 있어 스프링 빈으로 자동 등록된다.
- 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본적으로 싱클톤 패턴을 사용한다. (유일하게 하나만 등록할 수 있음. 같은 스프링 빈이면 모두 같은 인스턴스다. )
- @SpringBootApplication 애너테이션에는 @ComponentScan을 포함하고 있어 자동으로 스프링 빈으로 등록된 @Component를 스캔한다.
- 결국 @SpringBootApplication이 달려있는 대표 Application 클래스가 포함되어있는 패키지 하위에서만 실행이 된다.
- @Autowired를 통한 의존성 주입은 스프링이 관리하는 객체에서만 동작한다. (스프링 빈으로 등록하지 않고, 내가 직접 생성한 객체에서는 동작하지 않음.)
2. 자바 코드로 직접 스프링 빈 등록하기
서비스와 레포지토리 클래스의 @Service, @Repository, @Autowired 없이 시작한다.
1) SpringConfig 클래스(@Configuration으로 표시) 생성하여 그 안에 @Bean으로 등록한다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository(); //구현체
}
}
이렇게 하면 스프링이 뜨면서 Configuration태그를 읽고 그 안의 Bean태그들을 스프링 빈에 등록해준다. 그 안의 로직 그대로.
** 참고
: 실무에서는 주로 정형화된 컨트롤러, 서비스, 레포지토리 같은 코드는 > 컴포넌트 스캔을 사용.
정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
(ex. 현재 MemoryMemberRepository인데,, 이것을 DbMemberRepository로 바꿔주는 과정.)
Dependency Injection 방법
1. 생성자 주입 >> 권장
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
2. 필드 주입
: 외부에서 접근이 불가능하다는 단점이 존재. 테스트 코드를 쓰기 위해서는 객체를 수정할 수 없는 필드주입은 비추..
@Controller
public class MemberController {
@Autowired
private MemberService memberService;
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
3. setter 주입
: set~이 public이어야 하기 때문에 주입받는 객체가 변경되는 문제가 생길 가능성이 있다.
+ 주입할 대상이 없는 경우에 오류가 발생하는데 @Autowired(required=false)를 통해 설정 가능.
@Controller
public class MemberController {
private MemberService memberService;
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
}
** 왜 생성자 주입을 사용해야 할까?
1) 객체의 불변성 확보 : 의존 관계에서 변경이 필요한 상황이 거의 없다.
2) 테스트 코드의 작성 : 테스트 코드는 가능한 순수 자바로 작성하는 것이 좋다. 또한 컴파일 시점에 객체를 주입받아 테스트 코드 작성이 가능해, 주입하는 객체가 누락된 경우 오류를 발견할 수 있다.
3) final 키워드 : 생성자 주입시 필드 객체에 final 키워드 사용가능하므로 컴파일 시점에 누락된 의존성을 확인할 수 있다. (다른 주입 방법들은 객체 생성 이후에 호출되므로 final 사용 불가)
'Programming > 김영한 스프링 강의' 카테고리의 다른 글
why Spring Boot? (0) | 2024.04.11 |
---|---|
의존성이 주입되는 과정... (1) | 2023.12.27 |
스프링 웹 개발 기초 (1) | 2023.12.19 |
스프링 그리고 빌드 (0) | 2023.12.18 |