컨트롤러, 서비스, 레포지토리를 만들었으니 이제 이것을 화면으로 구성
멤버 컨트롤러를 만들어야 한다.
멤버 서비스를 통해서 만들어야 한다.
이렇게 하는 것을 의존 관계라고 합니다.
컨트롤러 어노테이션을 달으면 스프링이 뜰 때 객체를 생성해서 스프링이 갖고 있습니다.
이를 빈을 관리한다고 합니다.
스프링 컨테이너안에 이러한 객체(빈)들이 관리됩니다.
MemberController도 그게 가능합니다.
근데 이제 이렇게 스프링 컨테이너가 가지고 있을 경우 그것을 새로 생성해서 쓸 필요 없이 이것을 스프링 컨테이너에 등록 된 것을 사용한다.(싱글톤 패턴)
한번 테스트
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService = memberService;
}
}
실행결과
Description:
Parameter 0 of constructor in hello.hellospring.controller.MemberController required a bean of type 'hello.hellospring.service.MemberService' that could not be found.
Action:
Consider defining a bean of type 'hello.hellospring.service.MemberService' in your configuration.
에러 발생
AutoWire를 했는데 스프링 컨테이너는 얘를 갖고 있지 않다!
어떻게 하는가? 스프링 컨테이너에게 서비스가 서비스인 것을 알려주자?!
어노테이션 @Service!
레포지토리도 등록
@Repository
이렇게 주입이 된다.
다음과 같이 의존성이 주입이 됩ㄴ디ㅏ.
@Service, @Controller, @Repository 다 컴포넌트의 일종이다.
위에 한 방식이 바로 컴포넌트 스캔과 자동 의존 관계 설정을 하는 방법입니다.
아무데나 골뱅이 @Component를 적으면 등록이 되는가?
-> 안된다.
HelloSpringApplication이 ㅠㅗ하모딘 곳에서 가능합니다.
패키지 하위만 짝 따라갑니다.
@ComponentScan 이 있으면 찾아서 간다.
스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다(유일하게 하나만 등록해서 공유한다.) 따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.
위에 적은 어노테이션들 삭제
package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService MemberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
자동 등록 대신 우리가 직접 하였다.
Controller는 어쩔 수 없이 AutoWired로 시작을 하게 해야 한다.
-> 한 줄만 적는 것이 더 편하지만 장단점이 다 있다.
정상 작동 확인
자바 코드로 설정하지 않고 과거에는 XML을 사용하였지만 지금은 자바 코드로 많이 설정
DI 필드주입, Setter 주입, 생성자 주입이 있다.
생성자를 통해서 생성자로 올라온다.
필드 주입
@Autowired private final MemberService memberService;
Setter 주입
private MemberService memberService;
@Autowired
public setMemberService(MemberService memberService){
this.memberService = memberService;
}
-> 단점
중간에 바꿀일이 없는데 public으로 두기 때문에 계속 바뀔 수 있는 위헙성이 있습니다.
생성자 주입
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService = memberService;
}
생성자를 통해서 주입하면 조립되는 시점이 싹 들어와서 정리된다.
의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
-> 우리의 경우 memory 방식으로 구현한 DB를 변경해야 한다.
아직 데이터 저장소가 선정되지 않았기 때문에 interface로 구현하였다.
바꿀때 기존에 있는 코드를 변경하지 않는 방법
그거를 하려면 구현체를 바꾼다.
스프링 빈을 고친다.
컴포넌트 스캔시는 많은 것을 바꿔야 한다.
@Autowired를 통한 DI는 'helloController', 'MemberService'등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
-> 주석이 없으면 이러한 명령을 먹지 않는다!
스프링 컨테이너, DI 관련된 자세한 내용은 스프링 핵심 원리 강의에서 설명한다.