ApplicationContext를 Spring 컨테이너라고 한다.
Spring 컨테이너는 Spring에서 자바 객체들을 관리하는 공간을 말한다.
자바 객체를 Spring에서는 Bean이라고 하기 때문에, Spring 컨테이너에서 Bean의 생성부터 소멸까지를 관리하는 곳이라고 할 수 있다.
Spring 컨테이너는 @Configuration 이 붙은 AppConfig를 설정 정보로 사용한다. @Bean 어노테이션이 붙은 메서드를 모두 호출하여 반환된 객체를 모두 Spring 컨테이너에 등록한다.
스프링 컨테이너에 등록된 객체 → “스프링 빈”
컨테이너는 BeanFactory 와 ApplicationContext 으로 나눌 수 있다.
ApplicationContext컨테이너가 BeanFactory의 기능을 포괄하기에 때문에 대부분의 경우에는 ApplicationContext 을 사용한다.
Bean은 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트.
즉! 스프링 컨테이너가 관라하는 자바 객체를 뜻하며, 하나 이상의 Bean을 관리한다.
Spring에 Bean을 등록하는 방법으로는 아래 2가지가 있다. ( XML을 이용한 방법도 있지만 생략)
@Bean 어노테이션의 경우 메서드를 Bean으로 등록하기 위한 어노테이션
메서드에 붙여 메서드를 통해 반환되는 객체를 Bean으로 등록한다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
ex) @Service를 이용한 Bean 등록
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
public Long join(Member member){
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
@Component 어노테이션의 경우 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션
@Component
public class HelloComponet{
public HelloComponet() {
System.out.println("Hello Componet!!");
}
}
개발자가 작성한 Class를 Bean에 등록하기위해 Class 상단에 @Component를 붙였다.
@Component를 통해 등록된 Bean은 다른 Class에서 @Autowired를 사용해 의존성을 주입할 수 있다.
@Component
public class Brain {
. . .
}
@Component
public class Person {
private Brain brain;
. . .
}
}
❓ 의존성 ( D.I )
Person Class는 항상 Brain Class를 사용해야한다. 그러므로 Person은 Brain에 의존한다고 볼 수 있다.
public class Person {
private Brain brain;
@Autowired
public void setField(Brain brain) {
this.brain = brain
}
}
DI에는 필드 주입, 생성자 주입, setter 주입으로 3가지가 있지만, 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장
❗ @AutoWired 를 통한 DI는 스프링이 관리하 는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.@Controller, @Service, @Repository 어노테이션들은 @Component를 포함하기 때문에 가능하다.
ex) @Service의 구성
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component <---- 포함하고 있음
public @interface Service {
@AliasFor(
annotation = Component.class
)
String value() default "";
}