스프링에서 정형화되어있는 패턴
- Controller 통해서 외부 요청 받고,
- Service 통해서 비즈니스 로직 만들고,
- Repository에서 데이터 저장한다.
DI (의존성 주입, Dependency Injection)
- 의존 관계를 외부에서 주입(결정)해주는 것을 말한다.
- 클래스 간의 의존관계를 스프링 컨테이너가 자동으로 연결해주는 것
의존관계란?
의존 대상 B가 변하면, 그것이 A에 영향을 미친다 -> A는 B와 의존관계이다.
ex. memberService는 repository에 의존한다.
(repository가 변경된다면, service는 이에 영향을 받는다)
(service는 repository에 의존한다.)
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
의존 관계 주입 방법
1. 필드 주입 방법 (별로 안좋음,,)
@Controller
public class MemberController {
@Autowired private MemberService memberService;
}
2. Constructor 주입 방법
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
- 스프링이 뜰 때 스프링 컨테이너가 MemberController와 memberService를 연결해준다.
but 컨트롤러 내부에서 MemberService가 자동으로 등록되지는 않는다.
-> 컨트롤러에 service 주입 (DI)
- 스프링 최신버전에서는 생성자가 하나만 있는 경우 (@Autowired가 없어도) 자동으로 injection 해준다
3. Setter 주입 방법 (얘도 별로 안좋음,,)
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
}
- 단점
누군가가 memberController를 호출했을 때, setter(serMemberService)가 public으로 열려있어야 한다. -> 원래 setService는 처음에 한 번 쓰고 바꿀 일이 없는데, public으로 되어있으면 중간에 잘못 바꿀 수 있다 -> 문제 발생
의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
- 화면을 붙이고? 싶으면 -> controller랑 view template이 필요하다 -> MemberController를 만들어야 한다. -> 얘는 memberService를 통해서 회원가입+조회할 수 있어야 한다. == controller가 service를 의존한다.
@Autowired
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
- 스프링이 관리하는 빈(Bean)을 주입 받는다.
- 스프링이 뜰 때, 스프링 컨테이너가 MemberController를 MemberService와 연결해준다.
MemberService를 주입한다 (DI)
- 스프링이 관리하는 객체에서만 동작한다.
스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
스프링 빈을 등록하는 방법
1. 컴포넌트 스캔과 자동 의존관계 설정
- 컴포넌트 스캔 : @Controller, @Service, @Repository 사용 (얘네 모두 @Component를 상속받은 어노테이션이다)
- 스프링이 올라올 때, 컴포넌트와 관련된 어노테이션이 있으면, 스프링은 객체를 하나씩 다 생성해서 스프링 컨테이너에 등록을 한다. -> controller, service, repository가 스프링 컨테이너에 스프링 빈으로 자동 등록된다.
- cf) 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 싱글톤으로 등록한다. (유일하게 하나만 등록해서 공유한다.)
- @Autowired : 객체(컴포넌트)를 연결해주는 역할

-> hello.hellospring 패키지 내부 에 있는 파일만 컴포넌트 스캔을 한다.
2. 자바 코드로 직접 스프링 빈 등록하기
MemberService, MemoryMemberRepository 에 있는 @Service, @Repository, @Autowired 를 지우고 Springconfig에 @Configuration, @Bean 어노테이션을 통해 직접 의존성을 주입해준다.

- 장점 : 지금의 코드는 DB가 정해져있지 않다는 가정 하에, MemoryMemberRepository를 구현하고 나중에 다른 repository로 변경하는 방식이다. 이 때, 자바 코드로 직접 스프링 빈을 등록하면 코드를 하나도 수정하지 않고 DB와 Repository를 연결할 수 있다. (SpringConfig 파일에서 memberRepository()의 리턴값만 new DbRepository();로 바꿔주면 된다.)
참고/출처