본문 바로가기
Spring/Spring의 IoC

Bean

by 융디's 2024. 6. 15.
728x90
Bean

Bean

Bean

Spring IoC Container가 관리하는 객체
  • 만약 Bean으로 등록하지 않고 의존성을 주입하면 어떻게 될까?
    • 클래스가 굉장히 많고, 각각 의존 관계가 있을 때 이를 파악하기가 너무 어렵고, 그렇기에 관리가 힘들다
    A a = new A(new B(new E(new H(new M())), new F(new J(new M(0, new L())));
    • 따라서 의존성 주입이 필요한 객체를 Bean으로 등록하여 Spring IoC Container가 알아서 주입하도록 만드는 것!
  • 주요 특징
    • 관리의 자동화
      • Spring IoC Container에 의해 인스턴스화, 구성, 관리된다.
      • 개발자는 복잡한 객체 생성 및 관리 과정에 대해 신경 쓸 필요 없다.
    • 싱글턴 패턴(기본 패턴)
      • Spring에서의 Bean은 싱글턴 패턴을 따라 하나의 인스턴스만 생성된다.
      • 애플리케이션 내 해당 Bean에 대한 요청이 있을 때마다 동일한 인스턴스가 반환
    • 의존성 주입
      • Bean은 필요한 의존성을 자동으로 주입받는다.
      • 설정 파일, 어노테이션 등을 통해 구성할 수 있으며, 생성자 주입이나, 세터 주입 등의 방법을 사용 가능

Spring IoC Container

Bean을 인스턴스화, 구성 및 조립하고 생명주기를 관리하는 역할
  • IoC (Inversion of Control)
    • 프로그램의 실행 흐름이나 객체의 생명주기를 개발자가 제어하는 것이 아닌 외부에서 관리하는 것
  • 싱글톤 레지스트리라는 기능 존재
    • 레지스트리 key와 value 형태로 데이터를 저장하는 방법
    • 컨테이너는 빈 스코프가 싱글톤인 객체에 빈 이름을 Key로, 객체를 value로 저장
    • 따라서 의존성이 주입되어야 하는 객체가 bean으로 등록되어 있을 때

    spring은 bean의 이름을 이용해 항상 동일한 single Object를 반환하게 된다.

< IoC Container는 Bean을 어떻게 관리할까? >

  1. Spring Ioc Container 생성
  1. 빈 스포크가 싱글톤인 객체를 생성
  1. 빈으로 등록하기 위해 어노테이션기반, xml 기반, java Config 등의 메타데이터를 이용해 통일된 Bean Definition을 생성
  1. 빈으로 등록할 POJO와 Bean Definition을 통해 Bean 생성
  1. 빈 객체가 생성되면 IoC 컨테이너는 해당 빈에 자동으로 필요한 의존성을 주입한다.
  1. 객체를 초기화
  1. bean을 사용
  1. Spring Container가 종료 시 빈 스코프가 싱글톤인 객체들도 함께 소멸

Bean 등록 방법

Bean을 정의하는 방법은 크게 세 가지가 있다.
  1. XML 기반 구성
    • resource 폴더 하위에 XML 파일을 만든다.
    • XML 파일에 <beans> 태그 아래 <bean> 태그를 사용하여 Bean을 등록
      • id는 빈의 이름
      • class는 빈으로 등록하고자 하는 클래스가 위치한, 패키지명이 포함된 위치를 명시
      • setter로 의존성을 주입하고자 할 때는 <property> 태그 이용
      • 생성자를 통해서 의존성을 주입하고자 할 때는 <constructor-arg> 태그 이용
  1. 자바 기반 구성
    • @Configuration을 붙인 클래스는 자바 설정 파일로 등록이 가능하다.
    • 자바 설정 파일에서 @Bean을 사용하여 객체를 생성하고 반환하는 것만으로도 빈 생성 가능
    • 메서드의 이름 : 빈의 이름
    • 메서드의 반환 타입 : 빈의 타입
    • 반환되는 값 : 빈의 레퍼런스 값
    @Configuraiton
    public class JavaBasicConfig{
    	@Bean
    	public Book bookRead(){
    			return new Book();
    	}
    }
  1. 컴포턴트 스캐닝
    • @Component 붙은 모든 클래스들을 찾아 자동으로 Bean에 등록해 준다.
    • 컴포넌트 어노테이션 안에 직접 이름을 지정할 수도 있다.
    • @SpringBootApplication@ComponentScan을 포함하고 있다.
      • 기본적으로 컴포넌트 스캔이 붙은 자바 설정 파일이 위치한 패키지부터 탐색을 시작
      • basePackages : 해당 패키지에 속한 컴포넌트를 스캔
      • basePackageClasses : 해당 클래스가 속한 패키지를 스캔
    @Component() // 빈 이름 : boookRead
    public class BookRead{}
    @Component("bookService") // 빈 이름 : bookService
    public class BookService{}
    -----------------------------------------------------------------------------
    @Configuration
    @ComponentScan(basePackages ="book")
    @ComponentScan(basePackageClasses = BookService.class)
    public class JavaBasicConfig{
    }

컨테이너가 관리하는 객체 인스턴스 예제

  • Book 클래스
    public class Book{
    		private String title;
    		private int price;
    		// 생성자
    		public Book(String title, int price){
    				this.title = title;
    				this.price = price;
    		}
    		public String getTitle(){
    				return title;
    		}
    		public void setTitle(String title){
    				this.title = title;
    		}
    		public int getPrice(){
    				return price;
    		}
    		public void setPrice(int price){
    				this.price = price;
    		}
    }
  • JavaConfig 클래스 : Spring의 @Configuration을 사용하여 Bean 생성 및 의존성 주입 설정 정의
    • Book 클래스의 인스턴스를 생성한다
    • 이는 @Bean을 사용하여 스프링 컨텍스트에 의해 관리됨을 나타낸다.
    // DI 컨테이너에 의해 관리될 Book 인스턴스를 생성하는 설정 클래스
    @Configuration
    public class BookConfig {
    		@Bean
    		public Book book() {
    				return new Book("Java", 10000);
    		}
    }
  • Main 클래스 : 생성된 Bean을 사용하여 결과를 출력
    • getBean(Class<T> requiredType)
      • Bean의 이름을 사용하여 특정 Bean을 가져온다.
    // Spring 컨테이너를 통해 Book 객체를 가져와 사용
    @SpringBootApplication
    public class MainApplication {
    		public static void main(String[] args) {
    				ApplicationContext context = SpringApplication.run(MainApplication.class, args);
    				Book book = context.getBean(Book.class);
    				System.out.println("Book Title: " + book.getTitle()); // 자바
    				System.out.println("Book Price: " + book.getPrice()); // 200
    		}
    }
  • 만약 Book에 대해 Bean을 3개를 만들고 싶을 땐 어떻게 할까?
    • Spring에서 여러 인스턴스를 생성하려면, 각 인스턴스 별로 Bean으로 정의 추가해야 한다!
    • 메서드의 이름은 Bean의 이름이 된다.
    • getBean(String name, Class<T> requiredType)
      • 첫 번째 인자 : Bean의 이름 전달
      • 두 번째 인자 : 해당 Bean의 클래스 타입 전달
      • 인자 값들을 통해 특정한 Bean을 가져온다.
    @Configuration
    public class BookConfig {
        @Bean
        public Book book1() {
            return new Book("Java", 10000);
        }
    
        @Bean
        public Book book2() {
            return new Book("SpringBoot", 12000);
        }
    
        @Bean
        public Book book3() {
            return new Book("Microservices", 15000);
        }
    }
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            ApplicationContext context = SpringApplication.run(MainApplication.class, args);
            Book book1 = context.getBean("book1", Book.class);
            Book book2 = context.getBean("book2", Book.class);
            Book book3 = context.getBean("book3", Book.class);
    
            System.out.println("Book 1 Title: " + book1.getTitle() + ", Price: " + book1.getPrice());
            System.out.println("Book 2 Title: " + book2.getTitle() + ", Price: " + book2.getPrice());
            System.out.println("Book 3 Title: " + book3.getTitle() + ", Price: " + book3.getPrice());
        }
    }

Bean Scope

Bean의 생존 기간을 의미하며, DI 컨테이너는 Bean의 생존 기간도 관리한다.

< scope 종류 >

  • singletion(기본 스코프)
    • Bean 인스턴스가 하나 만들어지고, 요청 시 그 인스턴스를 공유하는 방식
    • 생성자를 private으로 선언하여 외부에서의 직접적인 인스턴스 생성을 막는다.
    • 싱글턴 인스턴스를 저장할 변수를 선언할 때 static으로 선언
    • 외부에서 싱글턴 인스턴스에 접근할 수 있는 정적 메서드(static)를 제공
  • prototype
    • Bean을 요청할 때마다 새로운 Bean 인스턴스가 만들어진다.
    • 각 객체가 독립적으로 값을 가진다.
    • 멀티 스레드 환경에서 오작동이 발생하지 않아야 하는 Bean일 경우 프로토타입을 사용
  • request
    • HTTP 요청이 들어올 때마다 새로운 Bean 인스턴스가 만들어진다
    • 웹 애플리케이션을 만들 때만 사용 가능
  • session
    • HTTP 세션이 만들어질 때마다 새로운 Bean 인스턴스가 만들어진다.
    • 웹 애플리케이션을 만들 때만 사용 가능

스코프 설정

자바 기반의 설정에서는 @Bean이 붙은 메서드에 @Scope를 추가하여 스코프를 명시
  • 오래 사는 순서 : singleton > session > request
  • 컨테이너에 의해 주입된 Bean은 자신의 스코프와 상관없이 주입받는 Bean의 스코프를 따른다.
    • 예를 들어 싱글톤 스코프 빈에 프로토타입 스코프 빈을 주입하면,
      프로토타입 빈은 실질적으로 싱글톤 빈과 동일한 수명을 가지게 된다.
        @Bean
        @Scope("singleton") // 생략 가능
        public Book singletonBook() {
            return new Book("Singleton Book", 10000);
        }
    
        @Bean
        @Scope("prototype")
        public Book prototypeBook() {
            return new Book("Prototype Book", 20000);
      }
728x90

'Spring > Spring의 IoC' 카테고리의 다른 글

Bean의 의존성 주입  (0) 2024.06.16
IoC와 DI  (0) 2024.06.12