인프런 🍀
[스프링 입문] 스프링 빈과 의존관계
의정부핵꿀밤
2022. 9. 6. 15:18
728x90
- 스프링에는 위와 같이 클래스 별로 의존 관계가 존재한다
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
- 위의 코드와 같이 생성자에 @Autowired 가 있으면 Spring이 자동으로 객체 생성 시점에 연관된 객체를 스프링 컨테이너에서 해당 스프링 빈을 찾아서 넣어준다
- 이렇게 객체 간의 의존 관계를 외부(spring)에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라고 한다
- @Autowired 를 사용하면 개발자가 직접 의존성을 주입할 필요 없이 스프링이 주입해준다
- 생성자가 1개만 있으면 @Autowired 는 생략이 가능하다
- 그러나 이 때 주입하는 객체가 스프링 빈으로 등록되어 있지 않다면 오류가 발생한다
- 위의 코드에서는 Controller는 @Controller 를 통해서 자동으로 스프링 빈으로 등록되었다
- 하지만 MemberService는 스프링 빈으로 등록되어 있지 않아서 위와 같은 오류가 발생한 것이다
스프링 빈을 등록하는 2가지 방법
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
1. 컴포넌트 스캔과 자동 의존관계 설정
컴포넌트 스캔 원리
- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다
- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다
- @Component 를 포함하는 아래의 어노테이션도 스프링 빈으로 자동 등록된다
- @Controller
- @Service
- @Repository
💡 위의 어노테이션들을 확인해보면 내부에 @Component를 포함하고 있기 때문에 스프링 빈으로 자동 등록이 가능한 것이다
💡 참고 : 스프링은 스프링 컨테이너에 스프링 빈을 등록할 떄, 기본으로 싱글톤으로 등록한다. 따라서 같은 스프링 빈이면 모두 같은 인스턴스인 것이다! 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다
2. 자바 코드로 직접 스프링 빈 등록하기
실습에서는 MemberService와 MemoryMemberRepository의 @Service, @Repository, @Autowired 어노테이션을 제거하고 진행한다
위와 같이 SpringConfig 클래스를 생성해서 추가한다
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();
}
}
- 그리고 SpringConfig 파일의 코드는 위와 같이 작성한다
- 이 때 MemberService 생성자에 MemoryMemberRepository를 주입해줘야 하므로 위와 같이 new로 MemberService를 생성할 때 넣어주면 Bean 객체가 주입된다
- 실무에서는 주로 정형화된 컨트롤러(@Controller), 서비스(@Service), 리포지토리(@Repository) 같은 컴포넌트 스캔을 사용한다
- 그러나 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정(config 파일)을 통해 스프링 빈으로 등록한다
- 변경해야 하는 경우 config 파일만 수정하면 되기 때문에 훨씬 편리하다
💡 이 때 controller를 어차피 스프링이 관리하기 때문에 @Controller를 이용해서 컴포넌트 스캔 시 올리고, @Autowired로 MemberService를 주입해준다
의존 관계를 주입하는 여러가지 방법
1. XML로 설정
XML 설정을 통해 의존관계를 설정할 수 있지만, 이는 최근에는 잘 사용되지 않는다
2. 필드 주입
@Autowired private MemberService memberService
- DI를 위처럼 필드로 주입할 수 있다
- 이는 중간에 변경할 수 없어서 권장되지 않는다
3. setter 주입
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
- 이를 하기 위해서는 setter가 public으로 선언되어 있어야 하는데, 그럼 외부에서도 누구나 값을 주입할 수 있게 된다
- 사실상 의존성 주입은 처음에 애플리케이션 조립(컴파일) 시에만 필요하고 이후에는 바뀔 일이 없어서 권장되지 않는다
- 거의 사용되지 않음!
4. 생성자 주입
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
- 위처럼 생성자를 통해서 주입하는 방법이다
- 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다
🚨 @Autowired를 통한 DI
● @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작한다
● 만약 스프링 빈으로 등록하지 않고, 내가 직접 new로 생성한 객체에서는 동작하지 않는다
● 따라서 @Autowired를 사용하려면 @Component나 @Bean을 통해 스프링 빈으로 등록해야 한다
728x90