..
[Spring Basic] 4. Spring Bean and Dependency Injection
Table of contents
- Spring Bean and Dependency Injection
- Annotation
- @Controller
- @Autowired
- How to register Spring Bean
- Component Scan and Auto Dependency Injection
- Component Scan의 대상(Range)
- Annotation
- Spring Bean Registration with Java code
- 의존성 주입 (Dependency Injection, DI)
- 생성자 주입 (Factory Pattern)
- 필드 주입
- Setter 주입
- 상황에 따라 구현 클래스를 변경해야 할 경우
- 직접 스프링 빈을 등록할 때의 장점
- 주의 사항
- 직접 스프링 빈을 등록할 때의 장점
- 의존성 주입 (Dependency Injection, DI)
Spring Bean and Dependency Injection
- 지금까지 MemberRepository, MemberService, Member객체를 만들고 Service를 통해서 member를 가입 시키면 repository에 저장이 된다
- 화면이 이 기능들을 붙일려면 Controller와 view template이 필요하다
- 그럴려면 controller가 memberService를 통해서 회원가입 하고, 데이터를 조회 할 수 있어야 한다.
- 이를 의존관계가 있다고 표현한다. (MemberController가 MemberService를 의존한다)
- 이 작업을 스프링스럽게 해보자
Annotation
@Controller
- Spring이 Spring Container에 memberController객체를 생성해서 관리를 한다. (이걸 spring container에서 spring bean이 관리 된다고 표현한다)
@Autowired
- 연관관계를 맺어준다
- 객체 생성 시점에 스프링 컨테이너에서 해당 스프린 빈을 찾아 주입한다 (DI)
- 생성자가 1개만 있으면 @Autowired는 생략 가능하다
How to register Spring Bean
1. Component Scan and Auto Dependency Injection
- @Controller, @Service, @Repository, @Autowired - 전부 @Component라는 annotation을 포함하고 있다
- 스프링은 스프링 컨테이너에 스프링 빈을 등록할때 Singleton으로 등록한다 (유일하게 하나만 등록 및 공유). 따라서 같은 스프링 빈이면 모두 같은 인스턴스다
Component Scan의 대상(Range)
- main method가 있는 동일 package (e.g., ericbyeric.firstspringdemo) 또는 하위패키지를 spring이 찾아서 등록한다.
- @ComponentScan이라는 annotation을 사용하면 다른 경로의 package에서도 등록은 가능 but 잘 하지는 않는다..
2. Java code
정형화된 패턴
- Controller - 외부 요청 받기
- Service - 비지니스 로직 만들기
- Repository - 데이터를 저장
Spring Bean Registration with Java Code
- 컴포넌트 스캔은 자동으로 스프링 빈을 등록하고 의존 관계가 설정이 된다. 이번엔 하나하나 직접 스프링에 등록하는걸 해보자
ericbyeric.springbasic package에 SpringConfig파일 생성
ericbyeric/springbasic/SpringConfig.java
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
- @Configutation, @Bean
- memberService와 memberRepository를 Spring에 등록하고 등록된 memberRepository를 memberService에 넣어준다.
- @Controller는 어쩔수 없이 두고 컴포넌트 스캔으로 올리간 controller가 @autowired로 의존성이 연결된다(Spring bean으로 등록된
memberService가 DI된다)
과거에는 XML로 설정 했으나 실무에서는 잘 사용하지 않는다
의존성 주입 (Dependency Injection, DI)
총 3가지의 의존성 주입 방법이 있다
- 생성자 주입
- 필드 주입
- setter 주입
생성자 주입 (Factory Pattern
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
- 가장 선호하는 방식!
- 조립 시점에서 생성자가 한번만 세팅하고 변경 못하도록 막아버릴 수 있다 (Factory Pattern)
필드 주입
@Controller
public class MemberController {
@Autowired private MemberService memberService;
...
}
- 단점 : 중간에 변경할 수 없다
Setter 주입
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberService(MemberService memberService){
this.memberService = memberService;
}
}
- 단점: 누군가가 MemberController를 호출했을때 이게 열려있어야 한다. 현재 public으로 열려있으니 중간데 변경이 될 수도 있다. 호출되면 안되는 메소드들은 호출되면 안된다. 잘못 바꾸면 문제가 생길수도 있다. 굳이 한번 세팅하면 변경할 필요가 없는 부분인데..
상황에 따라 구현 클래스를 변경해야 할 경우
- 우리가 회원 관리 예제 설계시 MemberRepository를 만들 때 아직 데이터 저장소가 선정되지 않았다고 했다. 그래서 Memory로 만들고 나중에 교체하자고 했었다. 그래서 interface를 설계를 하고 구현체로 MemoryMemberRepository를 쓰는 그림이 됐다.

- 기존에 운영중인 코드(controller나 memberService들)를 하나도 손대지 않고 나중에 MemoryMemberRepository를 교체 할 수 있는 방법이 있다.
- 그래서 이런 경우에 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
직접 스프링 빈을 등록할 때의 장점
- Repository를 교체하기 쉽다!
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new DbmoryMemberRepository();
}
}
- DbMemberRepository로 교체만 해주면 된다!
- 컴포넌트 스캔으로 조립했을 경우는 여러 코드를 바꾸어 주어야 한다
주의 사항
- @Autowired 를 통한 DI는 helloController , memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
- @Bean이 설정 안된 객체 안에서 @Autowired를 사용해도 적용이 안된다!
- 스프링 컨테이너에 올라 간 것들에게만 @Autowired가 동작한다!