WY J
학습 공간
WY J
  • 분류 전체보기 (95)
    • Java (38)
      • 알고리즘 (5)
      • 자료구조 (4)
      • 기초 (9)
      • OOP (10)
      • Collection (3)
      • Effective (5)
      • reator (2)
    • HTML&CSS (5)
    • macOS (3)
    • Git (5)
    • Network (5)
    • MySQL (2)
    • Spring Boot (31)
      • Core (5)
      • MVC (15)
      • Security (10)
    • 알고리즘 (1)
    • Cloud (3)
      • AWS (3)
    • Docker (1)
    • Project (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 글

hELLO · Designed By 정상우.
WY J

학습 공간

[Spring Core] Container, Bean Scope
Spring Boot/Core

[Spring Core] Container, Bean Scope

2022. 8. 12. 13:44

Spring 컨테이너(Container)와 빈(Bean)

 

Spring Container

스프링 컨테이너 란?

스프링은 스프링 컨테이너를 통해 객체를 관리하고, 컨테이너는 개발자가 정의한 Bean 설정 정보에 따라서 Bean 생성, 관리, 제거 등의 역할을 담당한다.

 

스프링 컨테이너는 의존성 주입을 통해 애플리케이션의 컴포넌트를 관리한다. 서로 다른 bean을 연결해 애플리케이션의 bean을 연결하는 역할을 한다. 개발자는 모듈 간의 의존 및 결합으로 인해 발생하는 문제로부터 자유로울 수 있고, 메서드를 호출하기 위한 매개 변수를 준비해서 전달하지 않는다.

 

스프링 컨테이너를 사용하는 이유?

객체를 생성하기 위해 new 생성자를 써야 했다. 이에 따라 애플리케이션에서 의존성이 높은 객체가 무수히 많고 서로 참조하게 되어있었다.

스프링 컨테이너는 구현 클래스들간의 의존을 제거하고 인터페이스에만 의존하도록 함으로써 객체 간의 의존성을 낮춰준다.

 

 

스프링 컨테이너의 생성 과정

 

 

  1. 스프링 컨테이너는 Configuration Metadata(설정 메타데이터)를 사용한다.
  2. 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 Bean을 등록한다.
  3. new AnnotationConfigApplicationContext(Config클래스.class)로 스프링에 있는 @Bean의 메서드를 등록한다.

 

// Spring Container 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

 

스프링 컨테이너를 만드는 다양한 방법들은 ApplicationContext 인터페이스의 구현체이다.

  1. AppConfig.class 등의 구성 정보를 지정해줘서 스프링 컨테이너를 생성한다.
  2. AppConfig에 있는 구성 정보를 통해서 스프링 컨테이너는 필요한 객체들을 생성하게 된다.
  3. 애플리케이션 클래스는 구성 메타데이터와 결합되어 ApplicationContext 생성 및 초기화된 후 완전히 구성되고 실행 가능한 시스템 또는 애플리케이션을 갖게 된다.

 

스프링 컨테이너는 인터페이스를 상속 받는 인터페이스가 존재하고, 그 인터페이스를 구현한 구현체가 존재한다. 이에 따라서 스프링 bean 조회에서 상속관계가 있을 시, 부모타입으로 조회하면 자식 타입도 함께 조회된다. → 자바 객체의 최고 부모인 object 타입으로 조회하면 모든 스프링 bean을 조회한다.

 

 

스프링 컨테이너의 종류

 

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스이다.
  • Bean을 등록, 생성, 조회하는 등 관리하는 역할을 한다.
  • getBean() 메서드를 통해 Bean을 인스턴스화할 수 있다.
  • @Bean이 붙은 메서드 명을 스프링 Bean의 이름으로 사용해 Bean 등록을 한다.

 

ApplicationContext

  • BeanFactory의 기능을 상속받아 제공하고 그 외의 부가기능 또한 존재한다.
  • ApplicationContext는 인터페이스이고, AnnotataionConfigApplicationContext는 ApplicationContext를 구현한 구현체 중 하나이다.

 

 

new와 생성자 주입 코드의 차이점

 

기존 new를 이용한 직접 객체 생성 방식

public class OrderServiceImpl implements OrderService {
	private final UserRepository userRepository = new UserRepositoryImpl();
    private final DiscountInfo discountInfo = new RateDiscountInfo();
    
    @Override
    public Order createOrder(Long userId, String itemname, int itemPrice) {
    	User user = userRepository.findByUserId(userId);
        int discountPrice = discountInfo.discount(user, itemPrice);
        return new Order(userId, itemName, itemPrice, discountPrice);
    }
}

생성자 주입을 통한 IoC & DI

public class OrderServiceImpl implements OrderService {
	private final UserRepository userRepository;
    private final DiscountInfo discountInfo;
    
    public OrderServiceImpl(UserRepository userRepository, DiscountInfo discountInfo) {
    	this.userRepository = userRepository;
        this.discountInfo = discountInfo;
    }
    
    @Override
    public Order createOrder(Long userId, String itemname, int itemPrice) {
    	User user = userRepository.findByUserId(userId);
        int discountPrice = discountInfo.discount(user, itemPrice);
        return new Order(userId, itemName, itemPrice, discountPrice);
    }
}

 

  • new를 사용하는 대신 생성자를 통해 의존 객체가 주입되고, 느슨한 의존 관계가 이루어진다.
  • userRepository와 discountInfo의 구현 클래스는 Bean 설정에 따라서 유연하게 변하게 된다.
  • 어떤 객체가 주입될지는 외부에서 결정하게 되고, OrderServiceImpl은 오로지 실행에만 집중하게 된다.

 

 


Spring Bean

 

Bean이란?

  • 스프링 컨테이너에 등록 및 관리되는 인스턴스화된 자바 객체를 의미한다.
  • @Bean이 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.
  • 클래스의 등록정보, getter/setter 메서드를 포함한다.
  • 컨테이너에 사용되는 설정 메타데이터로 생성된다. (설정 메타데이터 : 컨테이너의 명령과 인스턴스화, 설정, 조립할 객체를 정의)

 

 

Bean 접근 방법

ApplicationContext를 사용하여 bean 정의를 읽고 액세스할 수 있다.

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("cmarket", cmarketService.class);
// use configured instance
List<String> userList = service.getUsernameList();

 

 

BeanDefinition

Bean은 BeanDefinition(빈 설정 메타정보)으로 정의되고, BeanDefinition에 따라서 활용하는 방법이 달라지게 된다.

  • 속성에 따라 컨테이너가 Bean을 어떻게 생성하고 관리할지 결정한다.
  • @Bean or <bean> 당 각 1개씩 메타 정보가 생성된다.
  • Spring이 설정 메타정보를 BeanDefinition 인터페이스를 통해 관리하기 때문에 컨테이너 설정을 XML, Java로 할 수 있는 것이다.

 

  

 

Bean Scope

  • Bean Scope란, Bean의 사용 범위를 정의해 둔 속성이다.
  • BeanDefinition에 정의된 설정 메타 정보에 따라 Bean 객체 각각의 스코프가 정의된다.

 

Scope Description
singleton (Default) 각 Spring 컨테이너에 대한 단일 객체 인스턴스에 대한 단일 bean definition의 범위를 지정합니다.
prototype 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.
request 웹 요청이 들어오고 나갈때 까지 유지되는 스코프이다.
session 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프이다.
application 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프이다.
websocket 단일 bean definition 범위를 WebSocket의 라이프사이클까지 확장합니다. Spring ApplicationContext의 컨텍스트에서만 유효합니다.

 

 

 

Singleton Scope

  • Bean의 인스턴스를 오직 하나만 생성해서 사용하는 것을 의미한다.
  • 단일 인스턴스는 싱글톤 bean의 캐시에 저장된다.
  • 싱글톤 bean은 여러번 호출해도 모두 같은 인스턴스 참조 주소값을 가진다.
  • 싱글톤 방식은 여러 클라이언트가 하나의 인스턴스를 공유하기 때문에 싱글톤 객체는 무상태로 설계해야 한다.
    • 클라이언트가 값을 변경하면 안된다.
    • 읽기만 가능해야 한다.
  • 스프링 컨테이너의 기본값은 싱글톤이다.

 

공식 문서 : https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-scopes

 

 

 


Java 기반 컨테이너(Container) 설정

 

@Configuration & @Bean

@Configuration
public class 컨텍스트{
	@Bean
    public 빈클래스 빈메서드(){
    	return new 빈클래스();
    }
}

@Configuration : 컨텍스트 클래스 내부에 있는 bean 메서드를 실행하여 스프링 컨테이너에서 관리하도록 객체를 생성한다.

@Bean : bean 메서드임을 알리고 해당 메서드 실행 후 생성된 객체들은 스프링 컨테이너에서 관리된다.

 

 

 

AnnotationConfigApplicationContext를 사용하여 스프링 컨테이너를 인스턴스화하는 방법

ApplicationContext 구현은 아래와 같은 애너테이션이 달린 클래스로 파라미터를 전달 받고 있다.

  • @Configuration 클래스
  • @Component 클래스
  • JSR-330 메타데이터

 

@Configuration 클래스가 입력되면 @Configuration 클래스 자체가 BeanDefinition으로 등록되고, 클래스 내에서 선언된 모든 @Bean 메서드도 Bean 정의로 등록된다.

 

@Component 클래스와 JSR-330 클래스가 제공되면 BeanDefinition으로 등록되며, 필요한 경우 해당 클래스 내에서 @Autowired 또는 @Inject와 같은 DI 메타데이터가 사용되는 것으로 가정한다.

 

 

 

@Bean 선언

  • @Bean은 메서드-레벨 애너테이션이며, <bean />에서 제공하는 일부 속성을 지원한다.
  • @Configuration-annoted 또는 @Component-annoted 클래스에서 사용할 수 있다.

 

@Bean 애너테이션 사용

@Configuration
public class 컨텍스트{
	@Bean
    public 빈클래스 빈메서드(){
    	return new 빈클래스();
    }
}

@Configuration : 컨텍스트 클래스 내부에 있는 bean 메서드를 실행하여 스프링 컨테이너에서 관리하도록 객체를 생성한다.

@Bean : bean 메서드임을 알리고 해당 메서드 실행 후 생성된 객체들은 스프링 컨테이너에서 관리된다.

 

 

 

BeanDefinition이 있는 인터페이스를 구현하여 bean configuration을 설정할 수 있다.

public interface 인터페이스 {
    @Bean
    default 빈클래스 빈메서드() {
    	return new 빈클래스();
    }
}
@Configuration
public class 빈클래스 implements 인터페이스 {

}

 

 

Bean 사이에 의존성 주입

@Configuration
public class AppConfig {
    @Bean
    public Bean beanOne() {
    	return new BeanOne(beanTwo());
    }
    @Bean
    public BeanTwo beanTwo() {
    	return new BeanTwo();
    }
}

beanOne은 생성자 주입(beanTwo 메서드)을 통해 beenTwo에 대한 참조를 받는다.

 

 

 

애너테이션을 이용한 스프링 컨테이너 구성 방법

스프링의 자바 기반 구성 기능 특징인 애너테이션을 사용해 구성의 복잡함을 줄일 수 있다.

 

 

@Import 애너테이션을 사용하면 다른 클래스에서 BeanDefinitions을 가져올 수 있다.

@Configuration
public class ConfigA {
    @Bean
    public A a() {
    	return new A();
    }
}
@Configuration
// ConfigA.class를 import
@Import(ConfigA.class)
public class ConfigB {
    @Bean
    public B b() {
    	return new B();
    }
}

public static void main(String[] args) {
    // 컨텍스트 인스턴스화를 A,B 모두 하지않고, ConfigB만 제공
	ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
    
    // ConfigA도 사용 가능
    A a = ctx.getBean(A.class);
    B b = ctx.getBean(B.class);
}

ConfigA.class를 import한 ConfigB.class를 생성자 주입하여 getBean(A.class)가 가능해진다.

컨테이너 인스턴스화를 단순화할 수 있는 것이다. (두 개 생성 X)

 

 

 

@Import({컨텍스트1.class, 컨텍스트2.class, ...})형식으로 여러개의 컨텍스트들을 동시에 참조할 수 있다.

@Configuration
public class ServiceConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    @Bean
    public AccountRepository accountRepository(DataSource dataSource) {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class}) // bean 여러개 참조
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return new DataSource
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    // everything wires up across configuration classes...
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}

 

 

@Autowired 애너테이션은 의존 객체의 타입에 해당하는 bean을 찾아 주입하는 역할을 한다.

@Configuration
public class ServiceConfig {

    @Autowired
    private AccountRepository accountRepository;

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    private final DataSource dataSource;

    public RepositoryConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return new DataSource
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    // everything wires up across configuration classes...
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}

 

 

 

 

'Spring Boot > Core' 카테고리의 다른 글

[Spring Core] AOP(Aspect Oriented Programming)  (0) 2022.08.16
[Spring Core] Spring DI(Dependency Injection)  (0) 2022.08.12
[Spring Core] Spring Framework 모듈 구성  (0) 2022.08.10
[Spring Core] Spring Framework의 특징  (0) 2022.08.09
    'Spring Boot/Core' 카테고리의 다른 글
    • [Spring Core] AOP(Aspect Oriented Programming)
    • [Spring Core] Spring DI(Dependency Injection)
    • [Spring Core] Spring Framework 모듈 구성
    • [Spring Core] Spring Framework의 특징
    WY J
    WY J

    티스토리툴바