이제 AppConfig처럼 개발자가 직접 구현하는 것이 아닌 스프링에서 제공하는 DI컨테이너를 이용해 볼 것이다.
AppConfig
스프링 기반으로 수정
AppConfig
package hello.core;
import hello.core.discount.DisountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // Spring에서 제공하는 DI 컨테이너
public class AppConfig {
@Bean
public MemberService memberService(){ // 메소드 명 : 스프링 빈의 이름 (key)
return new MemberServiceImpl(memberRepository()); // 리턴 값 : 스프링 빈의 value
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), disountPolicy());
}
@Bean
public DisountPolicy disountPolicy(){
return new RateDiscountPolicy();
// return new FixDiscountPolicy();
}
}
클래스에는 Configuration annotation(설정을 구성한다는 의미) 을 부착해주고,
모든 메소드에는 @Bean annotation을 부착해준다.
이렇게 되면, @Bean이 부착된 메소드들은 스프링 컨테이너에 스프링 빈으로 등록된다.
등록될 때는 default값으로, 메소드 명을 스프링 빈의 이름으로 사용한다.
MemberApp에
스프링 컨테이너 적용
MemberApp
public class MemberApp {
//psvm (단축)
public static void main(String[] args) {
//3. Spring DI컨테이너 이용 (Application)
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); //모든 Bean을 관리해주는 것
MemberService memberService = applicationContext.getBean("memberService", MemberService.class); //name(주로 appconfig내 메소드명), return type
// 2. 수정된 순수 자바 코드 - Appconfig를 이용하여, DIP/OCP문제 해결
// 구현체의 생성과 의존관계 연결을 담당하는 "appConfig"객체를 생성함
// appConfig내 memberService(인터페이스)의 "생성+의존연결"을 담당하는 메소드를 호출해 memberServiceImpl(구현체)리턴받아 사용
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
//1. 순수 자바 코드 - DIP/OCP문제가 존재
//main는(클라이언트)에서 memberService 내 메소드를 실행하기 위해 구현체를 만듬
// memberService는 memberRepository를 의존하기 때문에, MemberServiceImpl코드 내에서 직접 MemoryMemberRepository를 생성해 사용했음.
// MemberService memberService = new MemberServiceImpl(); // 인터페이스 = 구현체
ApplicationContext를 스프링 컨테이너라고 한다.
지금 까지는 개발자가 AppConfig를 사용하여, 직접 객체를 생성하고 의존성을 주입(DI)했지만, 이제는 스프링 컨테이너를 이용한다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
다음과 같이 ApplicationContext객체를 생성한다. 매개변수로 AppConfig클래스를 넣어준다.
스프링 컨테이너는 @Configuration이 붙은 클래스를 설정(구성)정보로 사용하며,
@Bean이라고 적힌 메서드를 모두 호출하여, 반환된 객체를 스프링 컨테이너에 등록한다.
이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 한다.
지금까지는 개발자가 appConfig로 접근하여, 직접 조회했지만, 이제부터는 스프링 컨테이너를 통해 필요한 스프링빈(객체)를 찾는다.
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
다음과 같이 applicaitonContext.getBean메소드를 사용해서 찾을 수 있으며,
매개변수로 스프링 빈의 이름(기본값 메소드명), 리턴타입을 받는다.
기존에는 개발자가 직접 자바코드로 모든 것을 해야했다면,
이제는 스프링 컨테이너에 객체를 스프링 빈으로 등록하고, 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 변경되었다.
실행시켜보면 다음과 같다.
(결과는 같음)
다음 부터는 스프링컨테이너의 장점과 빈에대해 자세히 알아볼 것
'Backend > Spring' 카테고리의 다른 글
[Spring] 스프링 컨테이너와 빈 2) 스프링 빈 조회 (0) | 2021.09.30 |
---|---|
[Spring] 스프링 컨테이너와 빈 1) 스프링 컨테이너 생성 (0) | 2021.09.29 |
[Spring] 스프링으로 변경 1) IoC, DI, 컨테이너 (0) | 2021.09.24 |
[Spring] 순수 자바의 문제와 해결 3) 요구사항 변경 반영(OCP) (0) | 2021.09.24 |
[Spring] 순수자바의 문제와 해결 2) 관심사의 분리(SRP/DIP) (0) | 2021.09.23 |