[Spring] IoC,DI,컨테이너

CodeByHan·2024년 9월 18일

스프링

목록 보기
2/33

 Spring Framework에서는 DI, IoC, AOP가 3가지는 핵심 도구이다. 

제어의 역전 IoC(Inversion od Control)

  • 구현 객체가 직접 코드를 호출하는 것(스스로 프로그램의 코드를 제어)이 아니라,AppConfig처럼 외부에서 코드를 대신 호출,관리해 주는 것을 의미한다.쉽게 생각하면 제어 권이 넘어가기 때문에 제어의 역전(IoC)라 하는 것이다.
  • 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것
  • 간단하게 다른 객체를 직접 생성하거나 제어하는 것이 아니라 외부에서 관리하는 객체를 가져와 사용하는 것

AppConfig 예시

 public class AppConfig {
     public MemberService memberService() {
         return new MemberServiceImpl(memberRepository());
} 
     public OrderService orderService() {
        return new OrderServiceImpl(
                memberRepository(),
                discountPolicy());
}
     public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
}
     public DiscountPolicy discountPolicy() {
          return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}
  • AppConfig처럼 객체를 생성하고 관리하면서 의존 관계를 연결해 주는 것을 IoC 컨테이너 또는 DI 컨테이너라 한다.
    의존관계 주입에 초점을 맞추어 최근에는 주로 DI 컨테이너라 한다.
    또는 어샘블러,오브젝트 팩토리 등으로 불리기도 한다.

프레임워크 VS 라이브러리

  • 제어의 역전은 라이브러리와 프레임워크의 구분 기준이 될수도 있다.
  • 프레임워크가 내가 작성한 코드를 제어하고,대신 실행하면 그것은 프레임워크
  • 반면에 내가 작성한 코드가 직접 제어의 흐름을 담당하면 그것은 프레임워크가가 아니라 라이브러리

IoC가 필요한 이유?

  • 객체를 관리해주는 프레임워크와 내가 구현 하고자 하는 부분으로 역할과 관심을 분리해 응집도를 높이고 결합도를 낮추며, 이에 따라 변경에 유연한 코드를 작성 할 수 있는 구조가 될 수 있기 때문에 제어를 역전한 것이다.

의존성 주입(DI)

  • "스프링 컨테이너에서 객체 Bean을 먼저 생성해두고 생성한 객체를 지정한 객체에 주입하는 방식을 의존성 주입 이라고 한다."
  • 제어의 역전을 구현하기 위해 사용하는 방법이 DI

의존성 주입 방식

  • 필드 주입(Field Injection)
  • 수정자 주입(Setter Injection)
  • 생성자 주입(Constructor Injection)

필드 주입(Field Injection)

@Controller
public Class MemberController {
	
    @Autowired
    MemberService service;

}
  • 필드 주입은 클래스에 선언된 필드에 생성된 객체를 주입해주는 방식
  • 필드를 주입할때 @Autowired를 부여하는 방식
  • 가장 코드가 짧고 주입하기도 간편하고 보기에도 직관적이지만, 현재 가장 위험성이 많은 방식이다.
  • IntelliJ에서 필드 주입 사용하면 Field injection is not recommended이라는 경고 문구가 발생한다.
  • 외부에서 접근이 불가능하다는 단점이 존재하는데, 테스트 코드의 중요성이 부각됨에 따라 필드의 객체를 수정할 수 없는 필드 주입은 거의 사용되지 않게 되었다.
  • 필드 주입은 반드시 DI 프레임워크가 존재해야 하므로 반드시 사용을 지양

수정자 주입(Setter Injection)

@Controller
public class MemberController{

    private MemberService memberService;

	@Autowired
    public void setmemberService(MemberService memberService){
    	this.memberService = memberService;
    }
}
  • 수정자 주입은 클래스의 수정자(Setter)를 통해서 의존성을 주입해주는 방식
  • 수정자 주입 방식은 이어서 나올 생성자 주입 방식과는 다르게 주입받는 객체가 변경될 가능성이 있는 경우에 사용

하지만 실제 개발에서는 의존 관계 주입의 변경이 필요한 상황이 거의 없으며, 수정자 주입을 사용하게 되면 불필요하게 객체의 수정 가능성을 열어두게 되는데, 이는 OOP(객체 지향 프로그래밍)의 5가지 개발 원칙 중에 OCP(Open-Closed Principal, 개방-폐쇄 원칙)를 위반하게 된다.
따라서 수정자 주입이 아닌 생성자 주입을 통해 변경의 가능정을 배제하고, 불변성을 보장하는 것이 좋다.

생성자 주입(Constructor Injection)

@Controller
public class MemberController{

    private final MemberService memberService;

	@Autowired
    public MemberController(MemberService memberService){
    	this.memberService = memberService;
    }
}
  • 생성자 주입은 클래스의 생성자를 통해서 의존성을 주입해주는 방식
  • 생성자 주입은 인스턴스가 생성될때 1회 호출되는것이 보장
  • 생성자 주입시 필드에 final키워드를 사용할 수 있다.
  • 생성자 주입시에는 클래스 내 생성자가 한개,주입받을 객체가 Bean으로 등록

@Controller
@RequiredArgsConstructor
public class MemberController{
    private final MemberService memberService;
}

@RequiredArgsConstructor 로 필드를 포함한 생성자를 포함시켜주고 @Autowired 키워드를 생략해서 더 가독성이 좋은 코드로 사용이 가능

스프링 컨테이너

  • ApplicationContext를 스프링 컨테이너라 한다.
  • 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성) 정보로 사용한다.
  • 여기서 @Bean이라 적인 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.
  • ApplicationContext는 인터페이스다.

스프링 컨테이너 생성과정

  1. 스프링 컨테이너 생성

  • new AnnotationConfigApplicationContext(AppConfig.class)
  • 스프링 컨테이너를 생성할 때는 구성 정보(AppConfig.class)를 지정
  1. 스프링 빈 등록

  • 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록

빈 이름

  • 빈 이름은 메서드 이름을 사용한다.
  • 빈 이름을 직접 부여할 수 도 있다.
  • 반드시 항상 다른 이름을 부여
  1. 스프링 빈 의존관계 설정 - 준비
  1. 스프링 빈 의존관계 설정 - 완료
  • 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.
  • 단순히 자바 코드를 호출하는 것처럼 보이지만, 차이가 존재

빈(Bean)

  • 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트이다.
    즉, 스프링 컨테이너가 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다.

스프링 빈(Bean) 사용이유 ?

  • 큰 이유는 스프링 간 객체가 의존관계를 관리하도록 하는 것에 가장 큰 목적이 있다. 객체가 의존관계를 등록할 때 스프링 컨테이너에서 해당하는 빈을 찾고, 그 빈과 의존성을 만든다.

스프링 빈(Bean) 등록 방법
Spring Bean을 등록하는 방법은 대표적으로 3가지 정도가 있다.

  • xml에 직접 등록
  • @Bean 어노테이션을 이용
  • @Component, @Controller, @Service, @Repository 어노테이션을 이용

모든 빈 출력

  • ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름 조회
  • ac.getBean() : 빈 이름으로 빈 객체(인스턴스) 조회

애플리케이션 빈 출력

  • 스프링이 내부에서 사용하는 빈은 제외하고, 내가 등록한 빈만 출력해보자.
    스프링이 내부에서 사용하는 빈은 getRole()
    로 구분가능
  • ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈
  • ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈

싱글톤

  • @Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤은 보장하지 않는다.
  • 스프링 설정 정보는 항상 @Configuration을 사용하자
profile
노력은 배신하지 않아 🔥

0개의 댓글