AppConfig에 아래 어노테이션을 붙인다.
import org.springframework.context.annotation.Configuration;
-> @Configuration
@Configuration
: 애플리케이션의 설정 정보 라는 뜻! AppConfig에 설정을 구성한다는 뜻이다.import org.springframework.context.annotation.Bean;
-> @Bean
@Bean
: 각 메서드에 달아주면 스프링 컨테이너에 스프링 빈으로 등록됨위처럼 어노테이션 @Configuration과 @Bean을 붙이면, 스프링 구동 시에 스프링 컨테이너가 @Bean 안의 new를 이용해서 인스턴스를 생성한 후에 그 인스턴스의 참조값들을 메소드명:참조값 형식으로 컨테이너에 차곡차곡 집어넣는다!
이러한 원리로 같은 참조값만 반환하게 되므로 싱글톤이 되는 것이다.
MemberApp을 스프링 버전으로 바꿔보자!
<기존>
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
// MemberService memberService = new MemberServiceImpl();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find Member = " + findMember.getName());
}
}
<변경>
public class MemberApp {
public static void main(String[] args) {
// MemberService memberService = new MemberServiceImpl();
// AppConfig 설정
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
// 스프링 기반으로 변경하기
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find Member = " + findMember.getName());
}
}
스프링의 시작은 ApplicationContext 이다. 모든 것을 관리해주는 스프링 컨테이너 라고 보면 된다.
AnnotationConfigApplicationContext() 를 가지고 applicationContext 를 만들었다. AnnotationConfigApplicationContext() 는 어노테이션 기반이라는 뜻..(?)
파라미터로 AppConfig.class를 넣어주면 된다.
-> 그러면 AppConfig에 있는 환경설정 정보를 가지고, @Bean이 붙어 객체 생성한 것을 스프링 컨테이너에다가 전부 넣어 관리한다.
기존에는
MemberService memberService = appConfig.memberService();
이렇게 직접 찾아왔지만,
이제는
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
스프링 컨테이너를 통해 찾아와야 한다.
memberService 이라는 이름을 가진 객체를 찾을 거라는 뜻이고, MemberService.class는 타입을 뜻한다.
콘솔창을 보면 아래처럼 스프링 관련 로그가 몇 줄 나온다.
이렇게 각각 이름이 appConfig, memberService, memberRepository, orderService, discountPolicy인 빈들이 생성되어 컨테이너에 등록 되었다.
MeberApp뿐만 아니라 OrderApp도 마찬가지!
예) MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
에서 MemberService.class
!!
-> 클래스 타입이다. 객체 인스턴스는 new 문법으로 초기화 하여 클래스 내 멤버들에 접근할 수 있다. 하지만!!!! .class를 쓰면 클래스 타입으로 접근하여 클래스 속성과 각 멤버에 접근할 수 있다.
-> 이것을 '리플랙션' 이라고 한다.
즉, 자바 언어에서 클래스의 인스턴스가 아니라 타입 자체를 넘길 때는 .class 를 써야 한다.
ApplicationContext를 스프링 컨테이너 라고 한다.
기존에는 개발자가 AppConfig를 사용해서 직접 객체를 생성하고 DI를 했지만, 스프링 기반으로 전환하면 스프링 컨테이너를 통해 사용한다.
스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정 정보로 사용한다. AppConfig에서 @Bean이 붙은 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이처럼 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 한다.
스프링 빈은 @Bean이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다.
이제는 필요한 객체를 AppConfig를 사용하여 직접 조회할 필요가 없다. 스프링 컨테이너를 통해서 필요한 스프링 빈(객체)를 찾아야 한다.
스프링 빈은 applicationContext.getBean() 메서드를 통해 찾을 수 있다.