담비의 개발블로그

[Spring Boot] Bean이란? 본문

언어&프레임워크/Spring&Spring Boot

[Spring Boot] Bean이란?

담비12 2024. 6. 22. 20:53
빈(Bean)

 

"빈(Bean)"은 스프링 IoC(Inversion of Control) 컨테이너에 의해 관리되는 객체를 의미한다.

애플리케이션의 구성 요소(객체)를 관리하고 의존성 주입(Dependency Injection)을 통해 애플리케이션을 구성하는 역할을 한다

 

 

https://dambi1224.tistory.com/52

 

[Spring Boot]IoC 컨테이너란?

Inversion of Control  "Inversion of Control"은 직역하면 "제어 역전"이다.객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것을 의미한다. 조금 더 쉽게 말하자면 프로그램 제어

dambi1224.tistory.com

 

Bean의 주요 특징

 

 

  1. 생성 및 관리: 빈은 Spring 컨테이너가 생성하고 관리한다. 개발자는 빈을 직접 생성하는 대신, 컨테이너가 빈을 생성하고 의존성을 주입하도록 설정한다.
  2. 의존성 주입: 빈 간의 의존성을 주입하여 애플리케이션의 결합도를 낮춘다. 의존성 주입은 주로 생성자 주입, 필드 주입, 메서드 주입 방식으로 이루어진다.
  3. 스코프(Scope): 빈의 생명 주기를 정의하는 스코프가 있다. 기본 스코프는 싱글톤(singleton)이지만, 필요에 따라 프로토타입(prototype), 요청(request), 세션(session) 스코프 등을 사용할 수 있다.

 

 

Bean의 자바기반 설정
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
    
    @Bean
    public MyRepository myRepository() {
        return new MyRepositoryImpl();
    }
}

 

Spring Boot에서는 주로 자바 기반 설정을 사용하여 빈을 정의한다. @Configuration클래스에서  @Bean어노테이션을 사용한다.

 

Spring 에서는 주로 xml을 이용하였을텐데, 아래는 위와 똑같은 xml설정법이다.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myService" class="com.example.MyServiceImpl"/>
    
    <bean id="myRepository" class="com.example.MyRepositoryImpl"/>

</beans>

 

 

Bean의 어노테이션 기반 설정

 

import org.springframework.stereotype.Service;

@Service
public class MyService {
    private final MyRepository myRepository;

    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void performService() {
        // 서비스 로직
    }
}
import org.springframework.stereotype.Repository;

@Repository
public class MyRepository {
    public void save() {
        // 저장소 로직
    }
}

 

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

 

@SpringBootApplication 어노테이션은 @ComponentScan을 포함하고 있다. 이 어노테이션은 기본적으로 Application 클래스가 위치한 패키지와 그 하위 패키지를 스캔하여 @Service, @Repository, @Component, @Controller 어노테이션이 붙은 클래스들을 찾아 빈으로 등록한다.

 

위의 예시는 @SpringBootApplication 어노테이션이  @Service, @Repository어노테이션을 가져다 쓰고 있는 예시이다.

 

 

동작방식

 

  1. @SpringBootApplication이 선언된 클래스에서 애플리케이션이 시작된다.
  2. Spring Boot는 애플리케이션의 기본 패키지와 그 하위 패키지를 스캔하여 @Service, @Repository, @Component, @Controller 어노테이션이 붙은 클래스들을 검색한다.
  3. 검색된 클래스들은 Spring 컨텍스트에 빈으로 등록된다.
  4. 등록된 빈들은 필요에 따라 다른 빈에 의존성을 주입하여 사용한다.

 

Bean의 xml기반 설정
<!-- src/main/resources/beans.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myService" class="com.example.MyServiceImpl">
        <property name="myRepository" ref="myRepository"/>
    </bean>

    <bean id="myRepository" class="com.example.MyRepositoryImpl"/>
</beans>

 

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource("classpath:beans.xml")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

XML 파일에서 빈을 정의하고 Java Config에서 이를 로드할 수 있다.

 

의존성 주입
생성자 주입
생성자를 통해 의존성을 주입하는 방법이다. 가장 권장되는 방법으로, 주입할 필드가 final로 선언될 수 있다.
"final"키워드는 변수나 필드가 한 번 초기화된 이후에는 재할당될 수 없음을 의미한다. 불변 클래스를 만들기 위해서는 모든 필드가 "final"이어야 하며, 해당 클래스가 외부에서 상태를 변경할 수 있는 메서드를 제공하지 않아야 한다. 불변클래스는 객체가 생성된 후 상태가 변경되지 않기 때문에, 여러 스레드가 동시에 접근하더라도 객체의 상태가 일관되게 유지되기 때문에 스레드 세이프(thread-safe)하다. 이는 API 서버에서 여러 요청을 동시에 처리할 때 유용하다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {
    private final MyRepository myRepository;

    @Autowired
    public MyServiceImpl(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    // 서비스 로직
}

 

필드 주입
필드를 통해 의존성을 주입하는 방법이다. 코드가 간결해지지만, 주입할 필드가 final로 선언될 수 없다.
필드주입은 클래스 생성 이후에 값을 초기화하므로, 필드를 final로 선언할 수 없고, 이로 인해 클래스의 불변성을 깨뜨릴 수 있다. 그래서 보통 필드주입은 지양하는 편이다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {

    @Autowired
    private MyRepository myRepository;

    // 서비스 로직
}

 

Setter 주입
Setter 메서드를 통해 의존성을 주입하는 방법이다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {
    private MyRepository myRepository;

    @Autowired
    public void setMyRepository(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    // 서비스 로직
}

 

 

Bean 스코프

 

1. 싱글톤 스코프 (Singleton Scope)

 

기본 스코프로 컨테이너당 하나의 빈 인스턴스가 생성된다.

동일한 빈 정의를 여러 번 요청해도 같은 인스턴스를 반환한다.

주로 stateless 객체에 사용된다.

@Scope("singleton")
public class MySingletonBean {
    // ...
}

 

2. 프로토타입 스코프 (Prototype Scope)

 

요청할 때마다 새로운 빈 인스턴스가 생성된다.

각 요청마다 다른 객체를 반환한다.

주로 stateful 객체에 사용된다.

@Scope("prototype")
public class MyPrototypeBean {
    // ...
}

 

 

3. 리퀘스트 스코프 (Request Scope)

HTTP 요청당 하나의 빈 인스턴스가 생성된다.

웹 애플리케이션에서만 사용 가능하다.

각 HTTP 요청마다 다른 객체를 반환다.

@Scope("request")
public class MyRequestBean {
    // ...
}

 

 

4.세션 스코프 (Session Scope)

HTTP 세션당 하나의 빈 인스턴스가 생성된다.

웹 애플리케이션에서만 사용 가능하다.

각 HTTP 세션마다 다른 객체를 반환한다

@Scope("session")
public class MySessionBean {
    // ...
}