게으른 개발자의 끄적거림

스프링 @Bean 어노테이션이란?

끄적잉 2025. 3. 23. 23:11

Java의 @Bean 어노테이션에 대한 상세 설명

Spring 프레임워크는 자바 애플리케이션 개발 시 의존성 주입(Dependency Injection, DI)을 지원하는 강력한 기능을 제공한다. 이 중 @Bean 어노테이션은 스프링의 빈(Bean)을 수동으로 등록하는 데 사용된다. @Component, @Service, @Repository 등의 자동 감지(Annotation-based Component Scanning) 방식과 달리, 개발자가 직접 특정 객체를 빈으로 등록할 때 유용하다. 이 글에서는 @Bean 어노테이션의 동작 방식, 활용법, 주의할 점 등을 자세히 살펴본다.


 

1. @Bean 어노테이션이란?

@Bean 어노테이션은 스프링 컨테이너에 특정 메서드가 반환하는 객체를 빈으로 등록하도록 하는 역할을 한다. 이를 통해 개발자는 명시적으로 빈을 정의하고 제어할 수 있다.

기본적인 사용법

아래는 @Bean 어노테이션을 사용하는 가장 기본적인 예제다.

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

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

위 코드에서 @Configuration은 해당 클래스가 설정(Configuration) 클래스임을 나타내며, @Bean 어노테이션이 붙은 myService 메서드는 스프링 컨테이너에 MyService 객체를 빈으로 등록한다.


 

 

2. @Bean vs @Component 차이점

Spring에서 빈을 등록하는 방법은 크게 두 가지로 나눌 수 있다.

등록 방식 어노테이션 설명

자동 등록 @Component, @Service, @Repository 클래스 수준에서 선언하면 Spring이 자동으로 감지하여 빈으로 등록
수동 등록 @Bean 개발자가 직접 설정 클래스를 만들고, 메서드에서 객체를 반환하여 등록

자동 등록 (@Component 계열)

  • @Component, @Service, @Repository를 사용하면 Spring이 컴포넌트 스캔을 통해 자동으로 빈을 등록한다.
  • 기본적으로 패키지 내에서 클래스를 자동으로 탐색하기 때문에 설정이 간편하다.

수동 등록 (@Bean)

  • 특정 라이브러리의 클래스를 빈으로 등록할 때 유용하다.
  • 객체 생성 과정에서 추가적인 설정이 필요한 경우 사용할 수 있다.
  • 코드의 가독성과 유지보수성을 높이는 데 도움을 줄 수 있다.

예제:

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void doSomething() {
        System.out.println("Service is doing something");
    }
}

위 코드처럼 @Service를 사용하면 Spring이 자동으로 빈을 등록하지만, @Bean을 사용하면 보다 세밀한 제어가 가능하다.


 

 

 

3. @Bean의 주요 특징 및 동작 방식

(1) 메서드 이름이 빈의 이름이 됨

@Bean 어노테이션을 사용하면 해당 메서드의 이름이 스프링 빈의 기본 이름이 된다.

@Bean
public MyService myService() {
    return new MyService();
}

이 경우, 빈의 이름은 "myService"가 된다. 하지만 명시적으로 이름을 지정할 수도 있다.

@Bean(name = "customService")
public MyService myService() {
    return new MyService();
}

이렇게 하면 빈의 이름이 "customService"로 변경된다.


(2) 싱글턴(Singleton) 범위가 기본값

스프링의 빈은 기본적으로 싱글턴(Singleton) 으로 등록된다. 즉, @Bean 어노테이션을 통해 생성된 객체는 하나의 인스턴스만 유지된다.

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

위와 같이 myService() 메서드가 여러 번 호출되더라도, 항상 같은 인스턴스를 반환한다.

싱글턴이 아닌 매번 새로운 인스턴스를 생성하려면 @Scope 어노테이션을 활용할 수 있다.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Bean
@Scope("prototype")
public MyService myService() {
    return new MyService();
}

이렇게 하면 myService()가 호출될 때마다 새로운 객체가 생성된다.


 

4. @Bean을 활용한 의존성 주입

일반적으로 @Bean을 사용하여 다른 빈을 주입할 수 있다.

@Configuration
public class AppConfig {

    @Bean
    public MyRepository myRepository() {
        return new MyRepository();
    }

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

위 코드에서 myService는 myRepository를 생성자의 인자로 받아 의존성을 해결한다.


5. Factory Method 패턴 활용

@Bean을 활용하여 Factory Method 패턴을 구현할 수도 있다.

@Configuration
public class FactoryConfig {

    @Bean
    public CarFactory carFactory() {
        return new CarFactory();
    }

    @Bean
    public Car car(CarFactory carFactory) {
        return carFactory.createCar();
    }
}

위 코드에서 carFactory 빈을 생성한 뒤, 이를 이용해 car 빈을 생성한다.


 

6. 외부 라이브러리 객체 등록

Spring이 관리하지 않는 외부 라이브러리의 객체도 @Bean을 통해 등록할 수 있다.

import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
        dataSource.setUsername("user");
        dataSource.setPassword("password");
        return dataSource;
    }
}

이제 DataSource 빈이 등록되었으므로, 다른 클래스에서 주입하여 사용할 수 있다.


7. @Bean의 초기화 및 소멸 메서드 지정

스프링 빈은 생성된 이후 초기화 작업을 수행하거나, 애플리케이션 종료 시 자원을 해제할 수 있다.

@Bean(initMethod = "init", destroyMethod = "cleanup")
public MyService myService() {
    return new MyService();
}

여기서 init()과 cleanup()은 각각 초기화 및 종료 시 호출될 메서드이다.

public class MyService {
    public void init() {
        System.out.println("Initializing MyService");
    }

    public void cleanup() {
        System.out.println("Cleaning up MyService");
    }
}