내돈내고 내가 공부한것을 올리며, 중요한 단원은 저 자신도 곱씹어 볼겸 상세히 기록하고 얕은부분들은 가겹게 포스팅 하겠습니다.
섹션 4. 스프링 빈과 의존관계
1. 컴포넌트 스캔과 자동 의존관계 설정
- @Controller
스프링 컨테이너가 처음에 생성될때 @Controller 라는 에노테이션이 있으면 그 컨트롤러 객체를 생성해서 Spring IOC에 넣어 관리한다.
이걸 Spring IOC 컨테이너에서 SpringBean에 등록되어 관리된다고 부른다.
- @Autowired
필요한 의존 객체의 “타입"에 해당하는 빈을 찾아 주입한다.
1) 생성자
2) setter
3) 필드
위의 3가지의 경우에 Autowired를 사용할 수 있다. 그리고 Autowired는 기본값이 true이기 때문에 의존성 주입을 할 대상을 찾지 못한다면 애플리케이션 구동에 실패한다.
이번강좌에서는 우선 MemberService를 Controller에서 인식하도록 하는 방법에 대해 다루었다.
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;
}
}
컨트롤러의 코드는 위와 같다. @Controller가 있기 때문에 처음에 Spring 컨테이너가 생성될때 해당 컨트롤러 객체가 생성된다.
또한 @Autowired 를쓰면 MemberController() 생성자는 Controller의 생성자가 호출될때 Spring Bean에 등록되어있는 memberService 객체를 찾아서 넣어준다. 바로 Dipendency Injection (DI)이다.
DI는 총 3가지 방법이 있는데
1) 필드주입
2) setter 주입
3) 생성자 주입
이 있다. 자세한 예시는 저기 글 하단부에서 작성하겠다.
아직 문제가 있다! @Controller를 해두었기 때문에 Spring 컨테이너가 컨트롤러를 인식하고 시작시 생선한다는 것 까지는 논리적이다.
하지만 생성자의 인자로 받고싶은 memberService같은경우 어떠한 에노테이션도 사용하지 않았다. 그냥 진짜 class일뿐이다.
이를 Spring이 알아서 인식해줄리 만무했다. 다음 그림과 같은 상황인 것 이다.
따라서 MemberService 에는 @Service라는 에노테이션을 적어주고,
MemoryMemberRepository 에는 @Repository라는 에노테이션이 적어주었다.
의존성을 주입해주는 것 이다. 결과적으로 다음과 같아진다.
지금까지 한 @Controller @Service @Repository 등록방식이 컴포넌트 스캔 방식이다. Spring 컨테이너가 생성될때 component들을 빈에 싹 등록해준다.
이후 Autowired로 연결시켜주는 것 이 자동 의존관계 설정 이다.
컴포넌트 스캔 원리
- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
- @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
- @Controller
- @Service
- @Repository
마지막으로 그럼 아무 class 파일이나 모두 @Component를 써주면 다 스캔하고 등록할까?
아니다 !!
우리의 HelloSpringApplication은 package hello.hellospring 페키지에 들어있다.
따라서 hello.hellospring 를 포함한 하위에서만 찾아서 등록시킨다.
아 참고로 알려주신 내용이 있는데, 스프링 빈을 등록할떄는 기본이 싱글톤으로 저장된다. 따라서 같은 스프링 빈이면 모두 같은 인스턴스 이다.
위의 주소는 내가 정리해둔 싱글톤에 관한 글이다. 자세하게 설명해두었으니 읽어보면 도움이 될것 입니다.
2. 자바 코드로 직접 스프링 빈 등록하기
바로 위의 글에서는 Component들을 에노테이션을 사용하여 등록시켰지만, 이번시간에는 직접 JAVA 코드로 등록하는 방법에 대하여 배웠다.
다음 코드를 보면 @Configuration을 사용하였다. 이렇게 하면 Spring 컨테이너가 생성될때 이 파일을 읽는다.
package hello.hellospring.service;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
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();
}
}
위와 같이 하면 memberService() 랑 memberRepository() 둘다 spring bean에 등록을 하고, 스프링빈에 등록된 memberRepository() 를 memberService() 의 인자로 넣어준다. DI를 위해서 이다.
DI는 총 3가지 방법이 있는다.
1) 필드주입. 별로 안좋은 방식이다.
@Controller
public class MemberController {
@Autowired private MemberService memberService; // 필드 주입
// @Autowired
// public MemberController(MemberService memberService){
// this.memberService = memberService;
// }
}
2) setter 주입
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberService(MemberService memberService){
this.memberService = memberService;
}
}
단점은 누군가가 MemberController를 호출했을때 setter가 public으로 열려있어야 한다. 중간에 잘못바뀌면 문제가 된다.
3) 생성자 주입
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService = memberService;
}
}
가장 권장하는 방식이다. 의존관계가 실행중 동적으로 변할일은 거의 없기 때문이다.
주의!
@Autowired 를 통한 DI는 helloConroller , memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다.
스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
'BackEnd > Spring' 카테고리의 다른 글
[Spring] AOP : Aspect Oriented Programming (0) | 2022.01.14 |
---|---|
[Spring] 스프링 DB 접근 기술 (0) | 2022.01.14 |
[Spring] 회원 관리 예제 - 웹 MVC 개발 (0) | 2022.01.14 |
[Spring] 회원 관리 예제 - 백엔드 개발 (0) | 2022.01.12 |
[Spring] 스프링 웹 개발 기초 (0) | 2022.01.12 |
댓글