✅ 제어 역전의 개념
제어 역전 (Inversion of Control, IoC)은 소프트웨어 디자인 패턴 중 하나로, 프로그램의 제어 흐름을 개발자가 아닌 프레임워크 또는 컨테이너가 담당하는 것을 말합니다. 개발자가 객체의 생성과 관리를 직접 제어하는 것이 아니라 외부의 컨테이너가 그 역할을 맡는다는 의미입니다. 이를 의존성 주입(Dependency Infection)으로 구현되는데 의존성 주입은 객체 간의 의존 관계를 컨테이너가 설정해주는 방식으로, 객체가 필요로 하는 의존 객체를 직접 생성하는 것이 아니라 컨테이너가 객체를 생성하고 주입해주는 것입니다.
이를 통해 개발자는 핵심 비즈니스 로직에 집중할 수 있고, 컨테이너는 객체의 생명주기와 의존성 관리 등을 처리하여 프로그램의 유연성과 확장성을 향상시킬 수 있습니다.
-라이브러리 VS 프레임워크
- 라이브러리는 개발자가 필요한 시점에 라이브러리를 호출하여 사용합니다. 즉, 라이브러리를 사용하는 방법과 시점을 결정할 수 있습니다. 개발자가 제어 흐름을 직접 관리하고, 코드에서 필요한 기능을 선택적으로 사용할 수 있습니다.
- 프레임워크는 개발자가 프레임워크의 규칙과 구조에 따라 개발을 진행해야 합니다. 프레임워크가 제어 흐름을 주도하며, 개발자는 프레임워크가 제공하는 환경 안에서 필요한 코드를 작성합니다.
👉토비 책에서는 프레임워크는 분명한 제어의 역전 개념이 적용되어 있어야 한다고 나와있습니다.
✅ 오브젝트 팩토리
원래 UserDaoTest
는 UserDao
의 기능이 잘 동작하는지 테스트하려고 만들었지만, 현재는 UserDao
에서 어떤 ConnectionMaker
을 구현한 클래스를 사용할지까지 결정하고 있습니다. 다른 책임과 기능을 떠맡고 있으니 이를 분리해보겠습니다.
- DaoFactory
package com.jhcode.spring.ch1.dao; public class DaoFactory { public UserDao userDao() { ConnectionMaker connectionMaker = new DConnectionMaker(); UserDao userDao = new UserDao(connectionMaker); return userDao; } }
객체의 생성 방법을 결정하고, 생성된 객체를 반환해주는 역할을 하는 클래스 객체를 팩토리(Factory)라고 부릅니다.
DaoFactory
에서는ConnectionMaker
의 구현 클래스의 생성을 결정하고, 이를 토대로UserDao
객체를 생성하고 반환하는userDao()
메소드가 존재합니다.
- UserDaoTest
public class UserDaoTest { public static void main(String[] args) throws ClassNotFoundException, SQLException { //==> DaoFactory로 코드 이동 //ConnectionMaker connectionMaker = new DConnectionMaker(); //UserDao dao = new UserDao(connectionMaker); //Factory에서 결정하고 생성한 Dao 객체를 반환받아 사용함. UserDao dao = new DaoFactory().userDao();
DaoFactory
에서 생성한UserDao
객체를 반환 받아 사용합니다. 이제UserDaoTest
에서는UserDao
가 어떻게 만들어지고, 어떻게 초기화되어 있는지 신경 쓰지 않아도 됩니다. 관심사와 책임의 분리가 이루어진 것입니다.UserDao
와ConnectionMaker
은 애플리케이션의 오브젝트를 구성하고 그 관계를 정의하는 책임을 맡고 있습니다. 이를 실질적인 로직을 담당하는 컴포넌트라고 합니다. 반면,DaoFactory
는 컴포넌트의 구조와 관계를 정의한 설계도 같은 역할을 한다고 볼 수 있습니다.
✅ 스프링의 IoC
이제 DaoFactory를 스프링에서 사용이 가능하도록 변신시켜 보겠습니다.
- 빈(bean)
스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 객체를 빈(bean)이라고 부른다.
- 빈 팩토리(bean factory)
빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(bean factory)라고 한다. 이를 좀 더 확장한 애플리케이션 컨텍스트(Application Context)를 주로 사용한다. 애플리케이션 컨텍스트는 IoC 방식을 따라 만든 빈 팩토리이다.
👉DaoFactory를 스프링의 빈 팩토리가 사용할 수 있는 본격적인 설정정보로 만들어 보겠습니다.
- DaoFactory
package com.jhcode.spring.ch1.dao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DaoFactory { @Bean public UserDao userDao() { ConnectionMaker connectionMaker = new DConnectionMaker(); UserDao userDao = new UserDao(connectionMaker); return userDao; } @Bean public ConnectionMaker connectionMaker() { ConnectionMaker connectionMaker = new DConnectionMaker(); return connectionMaker; } }
- @Configuration : 애플리케이션 컨텍스트, 빈 팩토리가 사용할 설정 정보라는 표시
- @Bean : 객체 생성을 담당하는 IoC용 메소드 표시
@Configuration 어노테이션을 통해 스프링에서
Application Context
(객체의 생성과 관계를 관리할 빈 팩토리의 일종)을 생성할 때DaoFactory
객체를 생성자의 파라미터로 주입하여Application Context
객체를 생성하게 됩니다. 어플리케이션 컨텍스트에서는 해당 객체를 관리할 수 있습니다.
- UserDaoTest
package com.jhcode.spring.ch1.dao; import java.sql.SQLException; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.jhcode.spring.ch1.domain.User; public class UserDaoTest { public static void main(String[] args) throws ClassNotFoundException, SQLException { ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class); UserDao dao = context.getBean("userDao", UserDao.class); User user = new User(); user.setId("whiteship"); user.setName("jhcode"); user.setPassword("mariaDB"); dao.add(user); System.out.println(user.getId() + " 등록 성공"); User user2 = dao.get(user.getId()); System.out.println(user2.getName()); System.out.println(user2.getPassword()); System.out.println(user2.getId() + " 조회 성공"); } }
ApplicationContext
는 @Configure 어노테이션이 붙은 객체를 관리합니다..getBean()
메소드를 통해서 @Bean 어노테이션이 붙은 메소드에서 메소드의 이름을 key로, 메소드를 통해 생성되어 반환받은 객체를 value로 반환하여 사용할 수 있게 됩니다.
✅ 애플리케이션 컨텍스트의 동작방식
스프링에서는 이 어플리케이션 컨텍스트를 IoC 컨테이너, 스프링 컨테이너, 빈 팩토리라고 부르기도 합니다. 어플리케이션 컨텍스트는 ApplicationContext
인터페이스를 구현했고, ApplicationContext
는 BeanFactory
인터페이스를 상속했기 때문에 일종의 빈 팩토리인 셈입니다.
우리가 기존에 사용한 DaoFactory
, 오브젝트 팩토리 방식과 @Configure 어노테이션을 사용한 ApplicationContext
방식을 비교해보겠습니다. DaoFactory
는 UserDao
를 비롯한 DAO 객체를 생성하고 DB 생성 오브젝트와 관계를 맺어주는 제한적인 역할을 했습니다. ApplicationContext
는 IoC를 적용해서 관리할 모든 객체에 대한 생성과 관계설정을 담당합니다. 대신 ApplicationContext
에는 DaoFactory
와 달리 직접 오브젝트를 생성하고 관계를 맺어주는 코드가 없고, @Configure 어노테이션이 붙은 클래스를 설정 정보 삼아 외부의 팩토리에 그 작업을 위임하고 결과를 가져다가 사용합니다.
애플리케이션 컨텍스트는 DaoFactory
클래스를 설정정보로 등록해두고 @Bean 어노테이션이 붙은 메소드의 이름을 가져와 빈 목록을 만들어 둡니다. 클라이언트가 애플리케이션 컨텍스트의 getBean()
메소드를 호출하면 자신의 빈 목록에서 요청한 이름을 찾아 반환합니다.
➡️ 그렇다면 빈 팩토리 대신에 AplicationContext
를 사용하는 이유는 무엇일까요? 다음과 같은 장점이 있습니다.
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
DaoFactory
처럼 IoC를 적용한 설정 클래스가 많아져도 이를 알거나 직접 사용할 필요가 없습니다. 애플리케이션 컨텍스트를 이용하면 일관된 방식으로 원하는 객체를 가져올 수 있고, 자바 코드를 작성하는 대신 XML처럼 단순한 방법을 사용해서 IoC 설정정보를 만들 수도 있기 때문에 훨씬 간편합니다.
- 애플리케이션 컨텍스트트 종합 IoC 서비스를 제공해준다.
오브젝트가 만들어지는 방식, 시점과 전략을 다르게 가져갈 수도 있고, 부가적으로 자동생성, 오브젝트에 대한 후처리, 정보의 조합, 설정방식의 다변화, 인터셉팅 등 오브젝트를 효과적으로 활용할 수 있는 다양한 기능을 제공합니다.
- 어플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다.
애플리케이션 컨텍스트의
getBean()
메소드는 빈의 이름을 이용해 빈을 찾아줍니다. 타입만으로 빈을 검색하거나 특별한 어노테이션 설정이 되어 있는 빈을 찾을 수도 있습니다.
✅ 스프링 IoC의 용어 정리
- 빈(Bean)
스프링 IoC 컨테이너가 관리하는 객체를 말한다. 어플리케이션에서 만들어지는 모든 오브젝트가 빈은 아니다. 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만을 빈이라고 부른다.
- 빈 팩토리(Bean Factory)
스프링의 IoC 컨테이너의 최상위 인터페이스이며 빈의 생성, 조회, 관리 등을 담당한다. 이를 확장한 애플리케이션 컨텍스트를 주로 사용한다.
getBean()
과 같은 메소드가 구현되어 있다.
- 애플리케이션 컨텍스트(Application Context)
빈 팩토리를 확장한 인터페이스로, 스프링의 핵심 컨테이너이다. 빈 팩토리의 기능을 모두 포함하며, 더 많은 기능을 제공한다. Application Context는 Bean Factory를 상속한다.
- 설정 메타정보(Configuration Metadata)
스프링이 IoC 컨테이너를 생성하고 빈을 관리하기 위해 참조하는 메타정보이다. XML, 어노테이션, 자바 코드 등 다양한 형식으로 작성할 수 있다.
- 컨테이너(Container), IoC 컨테이너
IoC 컨테이너는 빈 팩토리의 관점에서, 컨테이너 혹은 스프링 컨테이너는 애플리케이션 컨텍스트의 관점에서 주로 이야기한다.
- DI(Dependency Injection)
의존 관계 주입을 의미한다. 객체 간의 의존 관계를 코드 내에서 명시하지 않고, 외부에서 주입하여 관리하는 방식이다.
- 라이프사이클(Lifecycle)
빈의 생성부터 소멸까지의 전체 과정을 라이프사이클이라고 한다. 개발자가 직접 제어하지 않고 스프링 컨테이너, 빈 팩토리가 관리하게 되면 이를 IoC라고 하는 것이다.
프로젝트 환경
- IDE : STS3 - 3.9.18.RELEASE
- SpringFramework : 5.3.20
- Java : 11
- Maven
📖토비 스프링 3.1 -p88~101
🚩jhcode33의 toby-spring-study.git으로 이동하기
Uploaded by N2T