본문 바로가기
Framework/Spring

[토비의 스프링] Application Context에 대한 이해

by 코딩하는 랄로 2023. 11. 27.
728x90

이전까지 배웠던 것은 스프링이 추구하는 가치를 이해하고 스프링이 그러한 가치를 제공하기 위해 제공하는 기능을 보다 잘 사용하기 위한 사전 지식이다. 관심사를 분리하고 인터페이스를 통해 확장성을 가질 수 있도록 하고 객체의 생성과 관심 설정까지도 factory 클래스에게 맡겨서 코드가 점차 객체지향에 가까워지는 과정을 통해 여러 개념에 대해서 공부하였다. 이번에는 이전의 factory 클래스를 스프링을 사용하여 구현해봄으로써 스프링이 제공하는 강력한 IoC 컨테이너에 대해서 보다 깊게 알아보는 시간을 가지겠다.

 

 

 

Application Context이란?

Spring의 Application Context를 알기 위해서는 Bean 객체가 무엇인지 알아야 한다. Bean 객체란 단순하게 말하면 컨테이너에 의해 관리되는 객체이다. 이 말을 지금까지 배운 개념을 토대로 해석하면, 객체의 생성과 관계를 설정하는 spring container에서 생성되고 관리되는 제어의 역전(IoC)이 적용된 객체가 바로 Bean 객체인 것이다. 

 

이 때의 Bean의 생성과 제어를 담당하는 스프링의 핵심 IoC container를 bean factory라고 하는데, bean factory를 상속 받아 기능을 더욱 확장 시킨 것이 Application Context이다. Bean factory보다 기능을 더 확장시켰기 때문에 일반적으로 Application Context를 주로 사용한다.

 

일반적으로 Bean factory(= IoC container)라고 지칭할 때엔느 Bean의 생성과 제어의 관점에서 이야기를 하는 것이고 Application Context(= container)라고 지칭할 때에는 스프링이 제공하고 있는 여러 기능을 모두 포함하여 이야기를 하는 것이다.

 

 

 

설정 정보

이전 글의 UserDaoFactory 코드를 보면 코드 안에 객체의 생성과 관계 설정 등이 다 담겨있는 것을 볼 수 있다.

public class UserDaoFactory {
    public DBConnection dbConnection() {
        return new SDBConnection();
    }
    public UserDAO userDAO() {
        return new UserDAO(dbConnection());
    }
}

 

이와는 달리, Application Context는 이러한 정보를 직접 담지 않고 설정 정보를 담고 있는 것을 가져와서 활용하는 IoC container이다. 여기서 설정 정보란 application context 또는 bean factory가 IoC를 적용하기 위해 사용하는 메타 정보를 의미한다. 스프링에서 이러한 설정 정보를 만드는 방법은 여러가지가 있는데 위의 UserDaoFactory도 Application Context의 설정 정보로 변경할 수 있다.

 

이러한 설정 정보와 Application Context가 바로 애플리케이션의 설계도 역할을 하는 것이다. 어떠한 비즈니스 로직을 수행하지는 않지만, Application Context와 설정 정보에 따라 애플리케이션의 컴포넌트를 생성하고 관계 설정을 해줌으로 애플리케이션이 만들어지고 구성되는 것이다.

 

 

 

설정 정보로서의 UserDaoFactory

위에서 언급하였듯이, UserDaoFactory를 application context의 설정 정보로 수정하여 보겠다. 먼저, Spring이 해당 클래스를 설정 정보로 인식하기 위한 @Configuration 어노테이션을 추가한다.

 

그리고 @Bean 어노테이션을 오브젝트를 생성하는 메소드에 붙여주기만 하면 간단하게 UserDaoFactory를 Application context의 설정 정보로 사용할 수 있게 된다.

package com.chapter1.spring.dao;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserDaoFactory {

    @Bean
    public DBConnection dbConnection() {
        return new SDBConnection();
    }

    @Bean
    public UserDAO userDAO() {
        return new UserDAO(dbConnection());
    }
}

 

설정 정보를 만들었으니 이를 사용하는 Application Context를 생성하여야 한다. @Configuration 어노테이션을 사용하는 Application Context를 만들기 위해 Application Context를 상속 받는 AnnotationConfigApplicationContext를 이용한다. 해당 코드는 UserTest 코드에서 작성하여야 한다.

package com.chapter1.spring.test;

import com.chapter1.spring.dao.UserDAO;
import com.chapter1.spring.dao.UserDaoFactory;
import com.chapter1.spring.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.sql.SQLException;

public class UserTest {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        ApplicationContext context = new AnnotationConfigApplicationContext(UserDaoFactory.class);
        UserDAO us = context.getBean("userDAO", UserDAO.class);

        User user = new User();
        user.setId(1);
        user.setName("USER1");
        user.setNickName("Spring");

        us.add(user);

        System.out.println(user.getId() + " 등록 성공!!");

        User user2 = us.get(user.getId());
        System.out.println(user2.getName());
        System.out.println(user2.getNickName());

        System.out.println(user2.getId() + " 조회 성공!!");
    }
}

 

UserDaoFactory 설정 정보를 이용하여 ApplicationContext를 생성을 한 후, Application Context가 관리하는 Bean 객체를 getBean 메소드를 이용하여 사용할 수 있다. 이 때 첫번째 매개변수가 Bean의 이름인데 바로 @Bean으로 지정해준 메소드의 이름이다. Bean의 이름은 변경 가능하지만, default는 메소드의 이름으로 지정된다.

 

두번째 매개변수는 리턴 타입으로서 해당 Bean은 UserDAO를 리턴하기 때문에 해당 클래스로 지정해준다. 이제 코드를 돌려보면 잘 동작하는 것을 볼 수 있을 것이다. 이렇게 간단한 Appplication Context를 사용하였는데, Spring이 Application Context를 통해 제공하는 기능은 위의 간단한 작업과는 비교도 안 되는 여러 기능을 제공하고 있다.

 

 

 

Application Context의 동작 방식에 대한 이해

Application Context는 IoC 컨테이너, 스프링 컨테이너, 빈 팩토리 등 여러 이름으로 불리는 만큼 스프링에서 중요한 오브젝트이다.(그냥 스프링이라고 부르기도 할 정도로...) 그렇기 때문에 이를 단순히 사용하기 보다는 어떻게 동작하는지에 대한 이해과 동반된다면 보다 그 기능에 알맞게 사용할 수 있을 것이다.

 

@Configuration 어노테이션을 이용하여 UserDaoFactory를 설정정보로써 Application context를 생성하였다. 또한 해당 container 내의 userDAO 메소드를 호출하여 생성한 오브젝트를 getBean을 통해 전달해준다. 이 동작 과정을 그림으로 나타내면 다음과 같다.

 

 

Application Context는 설정 정보를 이용하여 Bean 목록을 등록하고 UserTest가 userDAO를 getBean으로 요청하게 되면 Bean 목록에서 조회 후 해당 Bean 객체를 생성하는 메소드 userDAO를 호출하여 UserDAO 객체를 생성하여 UserTest에게 넘겨준다.

 

여기서 주의할 점은, Application Context가 설정 정보를 토대로 생성될 때 Bean 객체를 생성하는 것이 아닌 Bean 목록을 작성 후 Client가 요청할 때에만 생성하여 넘겨준다는 점이다.

 

 

 

Application Context의 사용 이유

Application Context를 팩토리 오브젝트 대신 사용하는 이유는, 팩토리 오브젝트가 가지는 IoC의 개념에도 객체지향을 적용하여 보다 유연하고 확장된 IoC기능을 사용할 수 있기 때문이다. 구체적으로 두 가지를 비교하면서 Application Context의 사용 이유에 대해서 알아보자.

 

먼저, 일반적으로 팩토리 오브젝트를 사용할 때, 사용자는 필요한 오브젝트를 가져오기 위해 어떤 factory를 사용하여야 하는지 알고 있어야 한다. 이는 factory 가 늘어날 수록 원하는 factory를 찾는 것도 번거롭고 해당 팩토리 오브젝트를 계속하여 생성해주는 것 또한 번거롭다. 하지만 Application Context를 사용할 경우, 일관된 방식으로 원하는 오브젝트를 가져올 수 있기 때문에 구체적인 팩토리 클래스에 대해서 몰라도 사용할 수 있다는 장점이 있다.

 

다음으로, Application Context는 일반적으로 객체를 생성하고 관계 설정을 해주는 factory 클래스와는 비교할 수 없는 여러 기능을 제공한다고 하였다. 이러한 기능에는 객체를 생성하는 방식, 시기, 자동 생성, 후처리 등 객체를 다양하고 효과적으로 활용할 수 있는 기능들이 존재한다.

 

이 외에도, getBean 메소드를 빈의 이름을 이용하여 빈을 찾아주는 것 이외에도 타입만으로 빈을 검색하거나 특별한 어노테이션 설정이 되어 있는 빈을 찾을 수 있는 등 다양한 빈 검색 방법을 제공한다.

 

 

 

 

 

 

 

 

참조 :  이일민, 토비의 스프링 3.1 - 스프링의 이해와 원리, 에이콘, 2012

728x90