[Spring] 의존성 주입(DI)과 IoC 컨테이너 개념

아는벌·2023년 2월 24일
0

web (2)

목록 보기
7/20

Spring for OOP (SOLID)

Single-responsiblity Principle

  • 하나의 클래스에는 하나의 책임만을 부여

Open-closed Principle

  • 확장에 대해서는 open, 수정에 대해서는 closed
  • 확장에 열려있다 -> 애플리케이션의 요구사항이 변경될 때 이 변경에 맞게 새로운 동작을 추가해서 애플리케이션 기능 확장
  • 수정에 대해 닫혀있다 -> 기존 코드를 수정하지 않고도 애플리케이션 동작을 추가/변경 가능
  • => 컴파일타임 의존성을 고정시키고, 런타임 의존성을 변경해라~

Liskov Subsitution Principle

  • 리스코프 치환 원친
  • 자식객체는 부모객체로 대체되어 사용 가능

Interface Segration Principle

  • 인터페이스 분리 원칙
  • 자신이 이용하지 않은 메소드에는 의존 X
  • 큰 덩어리의 인터페이스들을 구체적이고 작은 단 위들로 분리시킴으로써 클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 함

Dependency Inversion Principle

  • 의존성 역전 원칙
  • 클래스는 추상화에 의존해야지 추상화의 구체 클래스에 의존하면 X

의존성 주입(DI)

의존성이란?

  • 클래스 간에 의존(Dependency) 관계가 있음
  • 의존관계에 있는 한 클래스가 바뀔 때 다른 클래스가 영향을 받음

의존성 주입

  • 각 클래스간의 의존관계를 빈 설정(BeanDefinition) 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것
  • 클래스에 대한 의존성의 인터페이스화를 통한 코드 유연성 증대 + 클래스의 인스턴스를 외부에서 생성하여 주입
  • 인터페이스를 사이에 둬서 클래스 레벨에서는 의존 관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입
  • 의존성 주입을 받는다면 클래스 간의 결합도가 약해짐
  • 동작하는 클래스와 별개로 객체들의 의존성을 설정하는 외부 클래스(조립도)가 필요

생성자 주입

public class MemberServiceImpl implements MemberService{
    private MemberStroragy  memberStroragy;
    public MemberServiceImpl() {
        this.memberStroragy = new FileMemberStorage();    
     }
 }

MemberServiceImpl 클래스 내부에서 this.memberStroragy = new FileMemberStorage()과 같이 서비스를 직접 생성하는 경우 의존성 주입이 이루어지지 않고있다.

public class MemberServiceImpl implements MemberService{
    private MemberStroragy  memberStroragy;
    public MemberServiceImpl(MemberStroragy memberStoragy) {
        this.memberStroragy = memberStoragy;   
    }
}
public class AppConfig {
    MemberService memberService(){
        return new MemberServiceImpl(new FileMemberStoragy());
    }
}

MemberServiceImpl이 의존하고 있는 FileMemberStoragy가 외부에서 주입되고 있다!
Appconfig 클래스를 통해서 동작하는 클래스(MemberService)의 수정 없이 객체의 의존성을 설정할 수 있다. 자유롭게 기능을 추가, 삭제, 확장을 하면서도 코드는 수정되지 않아 OCP를 준수한다.

 public static void main(String[] args) {
        AppConfig appConfig = new AppConfig();
        MemberService memberService = appConfig.memberService();

AppConfig(조립도)를 통해 객체 관계를 설정한다.

IoC 컨테이너

IoC (Inversion of Control)

  • 제어의 역전
  • 전통적인 방법 - 제어권이 프로그래머에게 있음, 객체 생성 및 의존성을 직접 설정
  • 제어의 역전 - 제어권이 프레임워크에 있음!, 객체 생성 및 의존성 설정을 프레임워크에 위임

특징

  • IoC에서는 객체가 자신이 사용할 객체를 생성하거나 선택하지 않음!
  • 모든 객체는 제어 권한을 위임받은 특별한 객체(컨테이너)에 의해 만들어지고 사용됨
  • 스프링 빈 : 스프링 컨테이너에 의해 관리되는 스프링 객체로 어노테이션을 통해 관련 설정을 함
  • DI 방식으로 IoC를 시스템적으로 구현 가능

IoC 컨테이너란?

  • 객체 생성, 라이프사이클 관리, 의존성 설정을 담당하는 컨테이너(컨테이너; Bean을 담고 있는 그릇)
@Configuration
public class AppConfig{
	@Bean
    MemberService memberService(){
    	return new MemberServiceImpl(memberStoragy());
    }
    	@Bean
    BookService bookService(){
    	return new BookServiceImpl(feePolicy());
    }
}
  • @Configuration : 현재 자바 클래스를 객체 생성 및 연결 설정 정보 파일로 설정
  • @Bean : 컨테이너 안에서 메소드의 반환 인스턴스를 Bean으로 관리
  • 빈 이름은 중복되면 안됨!
public class MemberApp {
	public static void main(String[] args){
    	AnnotationConfigApplicationContext ac 
        		= new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService 
        		= ac.getBean("memberService", MemberService.class);
    }
}

AnnotationConfigApplicationContext가 IoC 컨테이너이다.

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스
  • 스프링 빈 관리 / 조회
  1. << interface>> BeanFactory
    -> 빈의 기본적인 관리(등록, 조회)
  2. << interface>> ApplicationContext
    -> ApplicationContext = BeanFactory 기능 + 부가 컨테이너 기능
  3. AnnotationConfig ApplicationContext
    -> ApplicationContext의 구현체, 스프링컨테이너의 실체

Bean 관리

  • 스프링 빈 설정 방법 1) xml 2) java config(snnotation)
  • 스프링 컨테이너는 BeanDefinition을 이용하여 빈 생성

getBean()

  • 입력한 파라미터로 빈 구분이 가능하다면 컨테이너는 적절한 빈을 반환함
// getBean(빈이름, 타입)
ac.getBean("memberService", MemberService.class);
// getBean(타입)
ac.getBean("memberService");	// 빈 이름으로만 
ac.getBean(MemberService.class); 	// 부모 타입으로만
ac.getBean(MemberServiceImpl.class); 	// 구체 타입으로만
ac.getBean("memberService", MemberServiceImpl.class);
  • 조회 대상이 모호할 경우
    - 부모타입으로 조회 시, 자식 타입도 함께 조회됨
    • 자바 객체 최고 부모인 Object 타입으로 조회 시, 모든 스프링 빈 조회 가능
  • 특정 타입의 모든 자식 타입 조회 - getBeansOfType()

싱글톤 패턴

  • 어플리케이션 내에 하나의 인스턴스가 존재하도록 강제하는 패턴
  • 하나만 만들어진 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근 가능(공유)

사용법

  1. 클래스 밖에서는 오브젝트 생성을 못하도록 기본 생성자를 private 지정
  2. 싱글톤 객체를 저장할 수 있는 자신과 같은 타입의 static 필드 정의
  3. getInstance() 메소드를 통해 이미 만들어져 있는 static 필드애 저장해둔 오브젝트를 반환

싱글톤은 안티패턴

  • 안티패턴 : 실제 많이 사용되는 패턴이지만 비효율적이거나 비생산적인 패턴
  • private 생성자를 갖고 있어 상속 불가
  • 클래스 사이의 강한 의존성
  • 추상화 개념 사용 어려움
  • 객체지향적이지 않음
  • 테스트하기 어려움
  • 서버 환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못함

IoC 컨테이너의 싱글톤 지원

  • 싱글톤의 단점을 프레임워크 레벨에서 보완
  • 객체 인스턴스를 싱글톤으로 관리(새로운 객체 생성하는 것도 가능)
  • 싱글톤 객체를 생성하고 관리하는 기능 -> 싱글톤 레지스터
  • 모든 객체를 싱클톤으로 변경하기 위한 코드가 필요 없음
  • SOLID 원칙 준수

참고

https://velog.io/@sana/DI-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85Dependency-Injection-%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%B0%A9%EB%B2%95
https://ssoco.tistory.com/65
https://kotlinworld.com/64#%EC%-D%--%EC%A-%B-%EC%--%B-%EC%-D%B-%EB%-E%--%--%EB%AC%B-%EC%--%--%EC%-D%B-%EB%A-%B-%--%EC%--%B-%EB%--%BB%EA%B-%-C%--%ED%--%B-%EA%B-%B-%--%EA%B-%--%EB%-A%A-%ED%--%-C%EA%B-%--%-F

0개의 댓글