본문 바로가기
개발/Spring

[Spring] 스프링 컨테이너, Bean 등록 및 사용하기

by solchan98 2022. 2. 10.

이 게시글은 스프링 컨테이너와 Bean을 깊게 다루기 보다는 스프링 컨테이너와 Bean의 흐름을 이해하고 어떻게 사용하고 사용되는지를 알아보는 것이 목적이다.

스프링 컨테이너를 배우기에 앞서 알고있어야 하는 패턴이 있다. 바로 싱글톤 패턴이다. 스프링 컨테이너는 스프링에서 사용되는 객체(Bean)를 싱글톤으로 관리해주기 때문이다.

싱글톤 패턴이 무엇인지 간단하게 이해하고 스프링 컨테이너가 무엇인지 알아보자.

싱글톤 패턴이 뭔데?

싱글톤 패턴

어떠한 객체를 단 한 번만 생성하고, 생성된 객체를 어디서든지 참조할 수 있도록 하는 패턴이다.

다음 예제를 보고 이해해보자
프린터를 사용하는 프로그램을 생각해보자.

  • 프린터 객체
    1. static영역에 객체를 1개만 생성해둔다.
    2. printer 인스턴스가 필요하면 이 static 메서드를 통해서만 조회 가능하도록 설정한다.
    3. 외부에서 생성자 호출을 막기위해 private로 설정한다.
public class Printer {
    // 1번
    private static final Printer printer = new Printer();
    // 2번
    public static Printer getPrinter() {
        return printer;
    }
    // 3번
    private Printer() {
    
    }
    
    public void print() {
        System.out.println("출력!");
    }
  • 위 getPrinter()를 통해 Test에서 2개의 인스턴스를 만들어 사용해보자.
public class Test {
    // 1번 프린터 객체
    Printer printer1 = Printer.getPrinter();
    // 2번 프린터 객체
    Printer printer2 = Printer.getPrinter();
    System.out.println(printer1 == printer2)
    // True가 출력될 것이다.

위 출력 결과는 True가 나온다. 두 개의 프린터를 생성하였고 생성된 두 인스턴스를 비교해보면 같은 인스턴스 즉, 하나의 인스턴스임을 알 수 있다.

위와 같이 하나의 인스턴스를 사용하는 패턴을 싱글톤 패턴이라고 한다.

스프링 컨테이터와 Bean

스프링 컨테이너

스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리해준다. 즉, 싱글톤 컨테이너 역할을 하고 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다.

스프링 컨테이너에서는 싱글톤으로 관리되는 객체를 Bean이라고 한다.

1. Bean Factory

Bean Factory는 스프링에 등록된 Bean을 생성 및 관리하는 기본적인 기능을 제공한다.

2. Application Context

Bean Factory를 상속받고있기 때문에 Bean Factory와 마찬가지로 기본적인 기능을 제공한다. Bean Factory와 차이점은 AOP처리 DI와 IoC 등 많은 부분을 지원하고, Application Context는 컨테이너가 구동되는 시점에 Bean들을 생성하는 방식으로 다르다.

Bean을 등록하는 방법?

Bean을 등록하는 방법은 여러가지가 있다.

1. @Configuration

스프링의 @Configuration 어노테이션은 어노테이션기반 환경구성을 돕는다.
@Configuration을 구현함으로써 클래스가 하나 이상의 @Bean 메소드를 제공하고 스프링 컨테이가 Bean정의를 생성하고 런타임시 그 Bean들이 요청들을 처리할 것을 선언하게 된다.

계산기 객체가 있다고 가정하고 Bean으로 등록해보자.

// AppConfig.java
@Configuration
public class AppConfig {
   @Bean
   public Calculator calculator() {
       return new Calculator;
}

위 코드처럼 @Bean을 통해 등록을 할 수 있다.

2. Bean으로 등록할 객체에 @Component 사용

Bean으로 등록할 객체에 @Component 어노테이션을 사용하면 스프링 컨테이너에 등록된다.

// Calculator.java
@Component
public class Calculator {
    ...
}

이후에 @Service, @Controller, @Repository를 사용하게 될 텐데 이 3개의 어노테이션은 @Component안에 모두 속해있다. 따라서 위 3개의 어노테이션 중 하나를 붙여도 동일하게 Bean으로 등록이 된다.

등록한 Bean 사용하기

간단하게 이해하기 위해 서비스 로직을 처리하는 객체를 하나 생성하고 여기서 등록된 Bean을 사용하는 예제를 만들어 보자.

  • 계산기 객체
  • 유저(Model)에 대한 로직을 처리하는 서비스 객체
    • 여기서 서비스는 앞서 배운 MVC 중 Model에 속하는 Service를 말한다.
  • Bean으로 계산기를 등록하고 서비스 로직에서 계산기를 사용하는 시나리오

1. 계산기 객체 생성

// Calculator.java
public class Calculator {
    // 더하기
    public Double add(x, y) {
        return x + y;
    }
}

2. AppConfig에 Bean으로 등록

// AppConfig.java
@Configuration
public class AppConfig {
   @Bean
   public Calculator calculator() {
       return new Calculator;
}

3. 등록한 Bean 사용하기

@Service는 @Component에 속하는 어노테이션이며 Model의 Service로직을 처리하는 객체에 등록하는 어노테이션이다. 지금은 넘어가도 좋다.

1. @Autowired

// UserSerrvice.java
@Service
public class UserService {
    // 선언
    private final Calculator calculator;
    // Bean 받기
    @Autowired
    public UserService(Calculator calculator) {
        this.calculator = calculator;
    }
    // 계산기 사용 메서드
    public void cal(a, b) {
        double result = calculator.add(a, b);
         System.out.println(result);
    }
}

인스턴스를 선언하고 @Autowired를 통해 생성자로 주입받아 계산기 인스턴스를 사용할 수 있다.
위와 같은 주입 방식을 @Autowired를 통한 생성자 주입 방식이라고 한다. 이와 다르게 필드 주입 방식도 존재하지만 문제점이 존재하기 때문에 생성자 주입 방식을 사용한다.
필드 주입 방식을 사용하지 않는 이유가 궁금하면 클릭하세요

1. @RequiredArgsConstructor(Lombok)

  • Lombok을 사용하면 코드를 좀 더 간결하게 만들 수 있다.
  • Lonbok 라이브러리를 추가한 후 사용이 가능하다.
  • 이 어노테이션을 Bean을 사용하려는 객체에 선언해주면 @Autowired와 생성자를 작성할 필요가 없다.
// UserSerrvice.java
@RequiredArgsConstructor
@Service
public class UserService {
    // 선언, 이제 사용 가능
    private final Calculator calculator;
    
    // 계산기 사용 메서드
    public void cal(a, b) {
        double result = calculator.add(a, b);
         System.out.println(result);
    }
}

이전 코드와 위 코드를 비교해보면 생성자 코드를 작성할 필요가 없어 코드가 훨신 간결해졌다.


해당 게시글은 공부를 하며 기록해 나가는 글입니다.
혹여나 정리 내용에서 잘못된 부분이 있다면 언제든 피드백 환영입니다!