개발자의 공부노트

스프링 컨테이너

2021. 6. 19. 23:40웹 개발/Framework

스프링 컨테이너


 스프링 컨테이너란 클래스에 의존성을 부여해주고 제어하기 위해서 외부에서 사용하는 스프링 인터페이스이다. 스프링 컨테이너를 통해서 IOC(제어의 역전), DI(의존성 주입)이 가능해지며 좋은 객체지향 코드를 작성할 수 있게된다. 

 

 

@Component
public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository;	//인터페이스
    
    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

 위와 같이 MemberRepository 인터페이스를 생성자 파라미터로 받아오는 클래스가 있다. 생성자 파라미터로 왜 구현체가 아닌 인터페이스를 넣는 것일까? 첫번째 이유는 바로 다형성이다. 인터페이스를 파라미터로 받게되면 외부에서 MemberServiceImpl을 호출할 때, 생성자 파라미터로 인터페이스 구현체들을 원하는대로 선택하여 호출할 수 있다. 이렇게 사용하면 자바의 다형성이 가져다주는 장점들을 유용하게 사용할 수 있다. 두번째는 구현체에 의존하지 않고 추상화에 의존하도록 하면서 의존성을 줄이는 것이다. 클래스에서 직접적으로 구현체에 의존하게 되면 구현체의 기능이 변경됐을 때 오류가 발생하게 될 확률이 높아진다. 또한 향후에 소스를 수정하거나 유지보수시 구현체에 의존하고 있으면 기능을 변경하는데 제약이 있을 수 있다. 따라서 추상화에 의존하도록 객체지향설계(DIP)를 하는 것이 올바른 방법이다.

 그렇다면 MemberServiceImpl 클래스를 외부에서는 어떻게 호출하고 제어해야 제대로 사용할 수 있을까? 그 역할을 해주는 것이 바로 스프링 컨테이너이다.

 

 

 

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() { return new MemberServiceImpl(memberRepository()); }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

 스프링 컨테이너를 사용하기 전에 컨테이너에서 사용할 빈을 지정해주는 DI컨테이너의 역할을 알아야만 한다. 위와 같이 @Bean 애노테이션을 MeberService와 MemberRepository 메서드에 등록해주면 스프링 빈이 등록이 되고 스프링 컨테이너가 빈을 호출하면 각 메서드의 return 값이 호출된다. memberService 빈을 호출하게 되면 먼저MemberServiceImpl 클래스가 참조객체로 호출된다. 여기에 생성자 파라미터로 memberRepository 빈도 함께 호출되어 MemoryMemberRepository 구현체가 파라미터로 들어가게 된다 .이것이 외부에서 의존성을 주입하는 DI컨테이너이다. 클래스에 @Configuration 애노테이션을 선언해주면 해당 빈들을 싱글톤으로 사용하겠다는 뜻이다. 만약 해당 애노테이션을 등록하지 않으면 객체의 싱글톤 패턴이 보장되지 않는다. 싱글톤 패턴에 대해서는 다음 글에서 설명하도록 하겠다.

 

 

 

public class MemberApp {

    public static void main(String[] args) {
    
    //스프링 컨테이너를 사용 안한 기존방식
    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, "test1");
    memberService.join(member);
    
    }
}

 ApplicationContext 인터페이스가 바로 스프링 컨테이너라고 할 수 있다. 스프링 컨테이너를 호출할 때 위의 DI컨테이너로 사용한 클래스(AppConfig)를 파라미터로 등록하여 호출해주면 DI컨테이너에 선언된 빈들이 자동으로 스프링 컨테이너의 빈 저장소에 등록된다. 기존 방식이라면 AppConfig 클래스를 참조객체로 호출하여 MemberServiceImpl 클래스를 호출한다. 그러나 이 방식으로 하게되면 스프링 컨테이너를 사용하는 것이 아니기 때문에 싱글톤 패턴을 사용하지 못한다. 즉, 호출시마다 서로 다른 주소의 객체가 생성되는 것이다. 그러나 스프링 컨테이너(ApplicationContext)를 통해 호출하게 되면 등록된 빈들을 getBean 메서드를 사용하여 자유롭게 호출할 수 있고, 호출된 빈 들은 싱글톤 패턴이 적용된다. 요청시마다 새로운 주소의 MemberServiceImpl 클래스가 호출되는 것이 아니라 한번 호출된 클래스를 공유하는 방식으로 사용할 수 있다. 이 것은 불필요한 메모리 낭비를 막을 수 있다. 그러나 모든 사용자들이 하나의 클래스를 사용하는 것이기 때문에 클래스 내부에 값이 변경될 수 있는 변수들은 주의해서 작성해야 한다.

 

이처럼 스프링 컨테이너를 활용하여 외부에서 클래스를 직접 제어할 수 있게되고, memberService 빈만 호출하여도 MemoryMemberRepository 클래스가 파라미터로 주입된 MemberServiceImpl 클래스의 생성자를 호출하여 불러올 수 있는 것이다. 상황에 맞게 파라미터로 들어갈 구현체 클래스들을 다양한 빈으로 설정하여 불러와 사용할 수 있다. 또한 스프링 컨테이너로 호출된 클래스들은 모두 싱글톤 패턴이 적용되어 공유하여 사용할 수 있는 장점이 있다.

 

 

'웹 개발 > Framework' 카테고리의 다른 글

MVC패턴과 Servlet  (0) 2021.07.06
스프링 핵심개념 DI, IOC  (0) 2021.06.09
스프링 프레임워크란?  (0) 2021.06.06