[Spring] 의존성 주입(DI) 알아보기 (2)

송어·2023년 11월 28일

SpringStudy

목록 보기
1/3

저번 포스팅엔 의존성에 대한 개념과 자바로 외부에서 의존성을 주입하는 방법에 대해 살펴보고, 마지막에 스프링에서 제공하는 기능을 이용해 주입방식을 살짝 바꾸어 보았다. 이전에 구현한 코드를 자세히 살펴보기 전 하나를 짚고 넘어가보고자 한다.

스프링 프레임워크를 사용하는 이유는?

스프링은 기본적으로 자바(Java)언어 기반의 프레임워크이다. 자바의 가장 큰 특징은 객체 지향 언어인데, 자바 언어로 객체 지향 언어가 가진 이점을 잘 살려서 좋은 객체 지향 애플리케이션을 만들려고 하다 보니 너무 신경써야할 일이 많다.
스프링은 객체 지향 언어를 활용해 개발함에 있어서 개발자가 객체 지향 원칙을 쉽게 지키면서 비즈니스 적인 부분에만 집중할 수 있도록 도와주는 프레임워크이다.

좋은 객체 지향 애플리케이션??

그렇다면 좋은 객체 지향 애플리케이션이란 뭘까??

내가 생각하는 좋은 객체 지향 애플리케이션이란 객체 지향의 특징을 잘 살리면서 개발자가 쉽게 관리할 수 있는 애플리케이션이라고 생각한다. 객체 지향 프로그래밍을 설명하는 여러가지 특징들이 있지만, 무엇보다 다형성을 활용해 좋은 객체 지향 설계 원칙들을 지킬 수 있도록 설계하는 것이다.

*스프링은 위에서 설명한 다형성을 극대화해 객체 지향 설계 원칙을 지키며 좋은 객체 지향 애플리케이션을 만들 수 있도록 지원해준다.**

이번엔 스프링에 대한 다양한 기능 중 의존성과 관련된 제어의 역전(Inversion of Control), 의존성 주입(Dependency Injection에 대해 자세하게 알아보겠다.

제어의 역전(IoC - Inversion of Control)

제어의 역전(IoC)이란 클라이언트 구현 객체가 다른 구현체를 지정, 호출하는 것이 아닌 프레임워크가 대신 호출해 줌으로써 제어의 흐름을 가져가는 것이다. 먼저 코드를 하나 보자.

public class GameController {

    private MapleStory game = new MapleStory();

    public void run() {
        System.out.println("game = " + game);
        game.monsterKill();
        game.levelUp();
    }
}

이전에 작성한 자바 코드이다. 제어에 역전을 제어역전으로 나누어 바라보자.
여기서 말하는 제어는 객체의 생명주기나 메서드 호출을 직접 제어(관리)하는 것이다.
위의 코드는 해당 객체를 직접 생성해 관리하고 있다.

public class GameController {

    private GameProgram game;

    public GameController(GameProgram game) {
        this.game = game;
    }

    public void run() {
        System.out.println("game = " + game);
        game.useGame();
    }
}

다음 코드에는 객체를 직접 생성하는 코드가 보이지 않는다. 여기서 역전제어한다는 것은 기존에 직접 관리하던 제어흐름을 말 그대로 역전시켜 외부에서 관리하는 것이다.
이 코드에서는 외부로부터 GameProgram타입의 game을 외부에서 인자로 받아 초기화 한다.

스프링에서 지원하는 제어의 역전(IoC)은, 의존성 주입이 필요한 여러 객체들을 개발자가 관리하는 것이 아닌 스프링 컨테이너를 활용해 관리하도록 지원해 개발자가 의존성 관리에서 벗어날 수 있도록 도와준다.

다음 코드를 살펴보자

@Configuration
public class GameConfig {

    @Bean
    public GameController gameController() {
        return new GameController(gameProgram());
    }

    @Bean
    public GameProgram gameProgram() {
        return new MapleStory();
    }
}

public class mainApp {
    public static void main(String[] args) {
//        GameConfig gameConfig = new GameConfig();
//        GameController controller = gameConfig.gameController();

        ApplicationContext ac =
                new AnnotationConfigApplicationContext(GameConfig.class);

        GameController bean = ac.getBean(GameController.class); // 컨테이너에서 bean 추출

        bean.run(); // 추출한 bean 사용
    }
}

이전 포스팅의 마지막 부분에 스프링에서 제공하는 기능을 약간 사용해 바꾸어본 코드이다.
위의 코드를 보면 @Configraion, @Bean이 보인다. 이것들은 뭐고
ApplicationContext ac = new AnnotationConfigApplicationContext(GameConfig.class);이 코드는 뭘까? 제대로 알아보기 전에 위에서 언급한 스프링 컨테이너가 뭔지부터 알아보자.

스프링 컨테이너

IoC컨테이너라고 부르는 스프링 컨테이너는 스프링에서 의존성 주입에 사용되는 자바 객체를 관리하는 공간을 의미한다. 자바 객체의 생명 주기를 컨테이너가 관리하며 이말고도 여러 추가적인 기능을 제공하는 역할을 한다. 이때 관리되는 자바 객체를 빈(Bean)이라고 부른다.

스프링 컨테이너 안에는 스프링 빈 저장소가 있는데 Map<K, V>와 같은 형태로 Key : 빈 이름
, Value : 빈 객체 형태로 빈을 저장하고 관리한다.

이 때 스프링 컨테이너에 빈을 등록할 때 사용하는 여러 방법들 중 하나가 @Configration@Bean어노테이션을 사용하는 것이다.

먼저 스프링 컨테이너는 @Configraion이 붙은 클래스를 설정 정보로 사용한다. 이 클래스에서 의존성 주입에 필요한 객체를 스프링 빈으로 등록하기 위해 메서드에 @Bean어노테이션을 붙여 반환하는 객체를 스프링 빈으로 등록한다.

@Bean이 붙은 메서드 명이 빈의 이름(Key)이 되고, 반환되는 객체가 스프링 빈으로 등록되는 객체(Value)가 된다.

위의 코드처럼 어노테이션을 붙여 등록하는 스프링 빈은 이런 형식으로 컨테이너에 담기게 된다.

스프링을 사용하기 전엔 주입할 객체를 AppConfig에서 직접 꺼내서 조회했지만 스프링 빈은 applicationContext.getBean()메서드를 사용해서 꺼낼 수 있다.

현재 @Configration@Bean을 사용해 빈을 등록한 방법은 개발자가 직접 빈을 정의하고 의존성을 설정하는 수동 주입 방식이다. 빈이 등록되는 방식을 살펴보기 위해 해당 방법을 사용하였고 향후 더욱 편리하고 범용적인 방식인 @Component@Autowired를 사용하는 자동 의존관계 설정 방식에 대해서도 다뤄보겠다.

스프링 빈(Spring Bean)

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container Otherwise, a bean is simply one of many objects in your application. ...이하 생략

스프링 공식문서 상에 정의된 스프링 빈에 대한 설명이다. 말 그대로 스프링 빈은 스프링 IoC컨테이너가 관리하는 자바 객체를 말한다. 우리가 기존에 사용했던 new 연산자를 입력해 객체를 직접 생성해 사용하는 방식이 아닌, 위 작성된 코드처럼 원하는 객체를 스프링 컨테이너에 넣어 스프링에 의해 생성되고 관리되는 객체를 빈(Bean)이라고 부른다.

다음 포스팅에선 빈의 생명주기 및 자동 주입에 대해 좀 더 살펴보겠다.

Reference

https://docs.spring.io/spring-framework/reference/core.html
https://dev-coco.tistory.com/163?category=1056309
https://hann-2.tistory.com/55

1개의 댓글