-
의존관계 주입과 스프링 컨테이너스프링/스프링 기본이론 2023. 1. 24. 20:05
객체지향 설계시 고려해야할 사항들
1. SRP 단일 책임 원칙
- 한 클래스는 하나의 책임만 가져야한다.
구현 객체를 생성하고 연결하는 책임은 구성만 관리하는 다른 Configuration 클래스를 생성해서 담당
클라이언트 객체는 실행 logic만 담당할 수 있게 함
2. DIP 의존관계 역전 원칙
- 프로그래머는 추상화에 의존하고 구체화에 의존 x
의존성 주입 원칙을 따르는 방법
생성자 주입 등을 통해서 새로운 객체를 주입하기 위해서는 구체화에 의존하지말고 추상화에 의존해야만 한다.
1번에서 말했던 Configuration 클래스에서 의존관계 주입을 통해 DIP 원칙을 따르면 된다.
3. OCP 원칙
- 소프트웨어 요소는 확장에는 열려 있으나 닫혀 있어야 한다.
애플리케이션을 사용 영역과 구성 영역으로 나눔
Configuration 클래스에서 의존관계를 변경하더라도 클라이언트 코드는 변경하지 않아도 된다.
즉, 소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다. (클라이언트는 변경 안해도 된다는 뜻)
ApplicationContext를 스프링 컨테이너라고 한다.
의존 관계를 주입할 때에 스프링 컨테이너를 통해 사용한다.
1. 의존관계 주입 - 관심사의 분리가 필요한 이유
public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository = new MemoryMemberRepository(); // 이후에 변경될 수 있음 }
위와 같은 경우에서 MemberService의 구현체는 MemberRepository를 사용하는데, memory를 쓸지, db를 쓴다면 어떤 db를 쓸지 모르는 상황이다. 변경될 수 있는 상황에서 이렇게 MemberService에서 변경을 시켜주는 것은 객체지향 설계의 원칙에 어긋난다. Service에서 Repository를 계속해서 변경해줘야하기 때문이다.
(여기서 MemberRepository는 인터페이스이고, Memory, db등은 구현체이다.)
public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } }
선언만 해준 다음에 추상화를 통해 직접 memberRepository를 선택하진 않는다.
public class AppConfig { public MemberService memberService() { return new MemberServiceImpl(new MemoryMemberRepository()); } }
이렇게 되면 memberService는 repository에 의존하지않고 자기 기능만 동작할 수 있다. 어떤 repository를 사용할 지는 service가 아니라 AppConfig에서 정해준다.
이걸 의존관계 주입이라고 한다.
의존관계 주입을 통해 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스의 의존관계를 쉽게 변경할 수 있다.
2. 스프링 컨테이너
스프링 컨테이너는 @Configuration이 붙은 AppConfig를 구성정보로 사용하고 @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.
@Configuration // Configuration이라고 선언 public class AppConfig { @Bean // 스프링 컨테이너에 등록 public MemberService memberService() { return new MemberServiceImpl(memberRepository()); } @Bean public static MemoryMemberRepository memberRepository() { return new MemoryMemberRepository(); } @Bean public OrderService orderService() { return new OrderServiceImpl(memberRepository(), discountPolicy()); } @Bean public DiscountPolicy discountPolicy() { return new RateDiscountPolicy(); } }
스프링컨테이너에 @Bean 어노테이션으로 생성된 메서드들을 스프링 빈이라고 한다. 스프링 컨테이너에 스프링 빈들이 등록되고, 이 스프링 빈들이 자동으로 의존관계를 설정해주는 것이다. 스프링 컨테이너는 메서드의 명을 스프링 빈의 이름으로 사용한다.
스프링 컨테이너의 사용
public class MemberApp { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); // AppConfig에 있는 설정을 가지고 스프링을 활용하는 것 // ApplicationContext는 스프링 컨테이너를 사용하기 위해 만들어줘야 하는 것 MemberService memberService = applicationContext.getBean("memberService", MemberService.class); // AppConfig에서 꺼내는데 앞에 name은 메서드 이름, 두번째 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.getBean으로 메서드를 호출할 때 매개변수 중 앞에는 AppConfig에 있는 메서드 명을 넣어줘야하며 두번째로는 사용하려는 클래스를 넣어줘서 반환타입을 맞춰줘야 한다.
'스프링 > 스프링 기본이론' 카테고리의 다른 글
의존관계 자동 주입 (0) 2023.01.31 컴포넌트 스캔 (0) 2023.01.30 @Configuration과 싱글톤 패턴 (0) 2023.01.30 스프링을 이용한 싱글톤 패턴 (0) 2023.01.30 싱글톤 패턴의 개념 (0) 2023.01.28