강한 결합과 약한 결합에서 이어지는 내용.
DI를 사용하기 위해서는 객체 생성이 필요했다. 그렇다면 언제, 어디서, 누가 객체 생성을 하는 걸까? 여기서는 main 메서드가 아니라, Spring 프레임워크
가 필요한 객체를 생성하고 관리하는 역할을 대신한다. Spring IoC 컨테이너*가 관리하는 Java 객체를 빈(Bean)
이라고 한다.
*Spring IoC 컨테이너: 'Bean'을 모아둔 컨테이너
Bean
을 등록하기 위해서는 @Component
애노테이션을 사용한다. Bean
으로 등록하고자 하는 클래스 위에 @Component
를 명시해주면, Spring이 @ComponentScan (컴포넌트 스캔)
을 통해 packages들을 확인하여 자체적으로 Bean으로 등록해준다.
@Component
public class MemoService { ... }
@SpringBootApplication
애노테이션을 통해 default 설정이 되어있는 경우도 있다.
@SpringBootApplication
public class MemoApplication { ... }
ApplicationContext
는, Bean의 생성, 관계설정 등의 제어를 담당하는 IoC 객체인 BeanFactory
등을 상속하여 기능을 확장한 컨테이너이다. 이를 통해서 Bean을 수동으로 가져올 수 있다.
public MemoService(ApplicationContext context) {
// 1. 'Bean'의 이름으로 가져오기
MemoRepository memoRepository
= (MemoRepository)context.getBean("memoRepository");
this.memoRepository = memoRepository;
}
- Spring 'Bean' 이름: 클래스의 앞글자만 소문자로 변경된 채로 저장된다.
- ex)public class MemoService → memoServcie
public MemoService(ApplicationContext context) {
// 2. 'Bean' 클래스 형식(class type)으로 가져오기
MemoRepository memoRepository
= context.getBean(MemoRepository.class);
this.memoRepository = memoRepository;
}
Bean
으로 등록했다면 사용을 해줘야한다. @Autowired
애노테이션을 통해 의존성을 주입(DI)해줄 수 있다.
불안정하기 때문에 권장하지는 않는다.
@Component
public class MemoService {
@Autowired
private MemoRepository memoRepository;
// ...
@Component
public class MemoService {
private MemoRepository memoRepository;
@Autowired
public void setDi(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
// ...
객체의 불변성
을 확보할 수 있기 때문에 생성자를 사용하여 DI하는 것이 권장되고, 실제로도 많이 사용한다. 생성자가 1개만 선언되어 있을 때는 @Autowired
를 생략할 수 있다.
@Component
public class MemoService {
private final MemoRepository memoRepository;
// @Autowired 생략
public MemoService(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
// ...
생성자 오버로딩으로 인해 생성자가 2가지 이상 선언되어 있을 때는 @Autowired
를 생략할 수 없다.
public class A {
@Autowired // 생략 불가
public A(B b) { ... }
@Autowired // 생략 불가
public A(B b, C c) { ... }
}
Lombok을 통해 의존성을 주입하는 경우에는 @RequiredArgsConstructor
애노테이션을 사용한다. @RequiredArgsConstructor
는 final
키워드로 선언된 멤버 변수를 파라미터로 사용하여 생성자를 자동으로 생성
한다.
@Component
@RequiredArgsConstructor
public class MemoService {
private final MemoRepository memoRepository;
// ...
Spring에서 3 Layer Annotation
은 Controller
, Service
, Repository
의 역할로 구분된 클래스들을 ‘Bean’으로 등록할 때, 해당 ‘Bean’ 클래스의 역할을 명시하기 위해 사용한다. 각 애노테이션 내부에는 모두 @Component
애노테이션이 추가되어있다.
@Controller
, @RestController
@Service
@Repository