의존성이 주입되는 과정...
컨트롤러 클래스에 @Controller 애너테이션을 달아주면
Spring Container라는 스프링 통이 있는데,
컨트롤러 객체를 생성해서 이 통에 넣어둔다. 그리고 스프링이 관리를 해준다.
new ~(); 로 객체를 생성하면 ?
다른 컨트롤러에서도 멤버 서비스를 받아서 쓸 수 있다........
그리고 사실 Service는 여러 개의 인스턴스를 생성할 필요가 없다..
이보다는
스프링 컨테이너에 등록을 해주고 얘를 써주는 것이 좋다.
어차피 스프링 컨테이너에 등록을 하면 딱 하나만 된다. (싱글톤 패턴)
ㅇㅋ 그럼 등록할게용
그러면 요렇게 표현할 수 있다.
필드에서 new~ 로 생성해주는 것이 아니라, 생성자 안에 인자로 MemberService를 넣어주어 MemberController가 생성될 때 자동으로 MemberService가 생성되도록!
그런데 여기서 @Autowired 애너테이션을 달아준다.
그러면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.!!! (이것을 우리는 의존성 주입 DI라고 부른다)
잉 근데 연관된 객체라는 것을 어떻게 알지!!!?????
그래서 저기에 빨간줄이 뜨는 것.... MemberService에도 이게 바로 연관된 객체야!!! 라고 알려주기 위해 표시를 해주어야 한다.
어떻게?
@Service 애너테이션을 통해 ㅎㅎ
오케이 달아줬더니 Controller의 빨간줄은 사라졌다.
얘를 인식한다는 이야기...
근데 여기서도 @Autowired 달면 MemberRepository에 빨간줄이 뜬다.
이친구도 인식할 수 있도록 애너테이션을 달아주자.
MemberRepository의 구현체인 MemoryMemberRepository로 가서 애너테이션을 달아주었다.
얘는 레포지토리야~ 라고 @Repository를 달아준다.
전체적인 그림은 이렇게 된다.
스프링 컨테이너 안에 memberService와 memberRepository가 스프링 빈으로 등록이 된다.
풀어서 말하면
MemberController의 객체를 생성할 때,
MemberService 객체가 필요하다.
스프링에서 찾아서 쓰려면 이게 바로 그 객체야~~하도록 그에 알맞는 애너테이션을 달아주어야 한다. @Service 달아주고,
또, MemberService의 객체가 생성될 때에는 MemberRepository의 객체가 필요하다.
이때 필요한 애너테이션이 @Repository. 달아주면 스프링 빈으로 등록이 되면서 찾아 쓸 수 있게 된다.
이렇게 되면 직접 MemberService service = new MemberService(); 이런 식으로 직접 객체를 생성해주는 것이 아닌,
외부에서 받아오도록 의존성을 주입해주게 되는 것이다.
cf)
의존성이 주입되지 않은 버전을 살펴보면 확실하게 느낌이 온다.
@Controller
public class MemberController {
private MemberService memberService;
public MemberController() {
this.memberService = new MemberService();
}
}
만약, 이런식으로 MemberController의 생성자에서 MemberService 객체를 생성한다면
...
두 클래스가 강하게 결합되게 된다.
또한, 객체들 간의 관계가 아닌, 클래스 간의 관계가 맺어지게 된다. . .
객체지향의 진짜 의미는 객체의 구현체가 어떤 것이든간에 같은 인터페이스를 구현했다면 인터페이스 타입으로 사용할 수 있어야 한다.
그러나, 이렇게 클래스 간의 관계를 맺게된다면 어쩔 수 없이 특정 구현체를 생성자 안에서 생성해야 한다....
이해가 잘 안되어서 직접 만들어 보았다.
그러면 MemberRepository 인터페이스를 상속받는 클래스를 두개 만드는 것이다.
1) MemoryMemberRepository implements MemberRepository
2) ExampleRepository implements MemberRepository
둘 다 MemberRepository를 상속받기 때문에
만약 위의 의존성 주입 버전에서는 둘 다 MemberRepository의 구현체가 된다면 서비스 생성 시 들어가게 된다...(**다 형 성 **)
그러나, 의존성 주입하지 않은 버전이라면...?
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService() {
this.memberRepository = new MemoryMemberRepository();
// this.memberRepository = new ExampleRepository();
}
서비스 클래스에서 바로 생성을 해야하기 때문에 "특정"한 인터페이스구현체를 직접 생성해주어야 한다.
이렇게 되면 확장성이 훠어어얼씬 떨어진다...
아.. 이래서 의존성 주입을 하는구나!( 그리고 이런 의존성 주입 방법에는 여러가지가 있다... 더 공부해야 할 것! )
결합도를 낮추고,,, 유연성을 확보!
스프링 프레임워크가 이것을 지원해준다..
스프링은 특정 위치부터 클래스를 탐색하고, 객체를 만들고, 이 객체들의 관계를 설정해준다. 그래서 스프링이 DI 컨테이너다.
그리고 이런 과정을 거치면 제어의 역전(IoC)가 일어난다. .
어떤 객체를 사용할지에 대한 책임은 프레임워크가 하고, 결국 사용 시 수동적으로 주입받는 객체를 사용하게 된다.
'Programming > 김영한 스프링 강의' 카테고리의 다른 글
why Spring Boot? (0) | 2024.04.11 |
---|---|
스프링 빈을 등록하는 방법(컴포넌트 스캔/자바 코드로 등록) (0) | 2023.12.27 |
스프링 웹 개발 기초 (1) | 2023.12.19 |
스프링 그리고 빌드 (0) | 2023.12.18 |