새소식

반응형
Java/Spring

스프링 빈(Spring Bean)이란?

  • -
728x90
반응형

스프링 빈(Spring Bean)

Spring IOC 컨테이너가 관리하는 자바 객체를 빈이라고 부른다. 이전 글에서 제어의 역전(IOC, Inversion Of Control)에 대해 알아봤는데 간단하게 설명하겠습니다.

예전의 자바 프로그래밍에서는 Class를 생성하고 new 키워드를 이용하여 객체를 생성한 후 사용했습니다.

하지만 Spring에서는 직접 new 키워드를 이용하여 객체를 생성하는게 아닌 Spring에 의하여 관리당하는

자바 객체를 사용한다. 이렇게 Spring에 의해 생성되고 관리되는 자바 객체를 Bean이라고 한다.

 

 

* 제어의 역전(IOC, Inversion Of Control)

일반적으로 에전 자바 프로그래밍에서는 객체들이 프로그램의 흐름을 결정하고, 각 객체를 직접 사용자가 생성하고

조작(객체를 직접 생성, 메소드 호출)했습니다. 즉, 모든 작업을 사용자가 제어하는 구조였습니다. 예를 들어 A 객체에서

B 객체에 있는 메소드를 사용하려면, B객체를 직접 A 객체 내에서 생성하고 메소드를 호출했습니다.

여기서 IOC를 적용할 경우, 객체의 생성 및 생명주기 관리를 IOC 컨테이너라는 특별한 관리자에게 맡깁니다. 사용자가 직접 객체를 생성하지 않고 객체의 생성 및 생명주기를 IOC 컨테이너가 컨트롤하게 됩니다. 즉, 사용자의 제어권을 다른 주체(IOC 컨테이너)에게 넘기는 것을 제어의 역전(IOC)라고 한다.

 

 

Spring Bean 으로 등록해서 사용하는 이유

1. 객체 생명주기 관리

  • new 키워드로 생성할 경우 객체의 생성과 파괴를 직접 책임져야 한다.
  • Bean 으로 등록하면 Spring IoC 컨테이너가 어플리케이션 시작 시점에 생성하고, 종료 시점에 정리까지 해준다.
  • 메모리 관리, 자원 반납(close) 같은 걸 훨씬 안전하게 처리 가능하다.

 

2. 싱글톤 관리(재사용)

  • new 키워드로 생성하면 호출할 때마다 새로운 객체가 만들어진다.
  • Bean(@Service, @Component, @Controller) 은 기본적으로 싱글톤 스코프 → 한번 만들어지면 여러곳에서 공유
  • 예) 데이터베이스 커넥션 풀, 서비스 로직 같은건 싱글톤으로 관리하는게 훨씬 효율적이다.

 

3. 의존성 주입(DI)

  • new 키워드로 생성 시 그 안에서 필요한 객체를 또 new 로 생성해야 한다. → 의존성이 강하게 결합된다.
  • Bean 은 Spring 이 생성하고 필요한 다른 Bean 들을 자동으로 주입(@Autowired, 생성자 주입) → 느슨한 결합
  • 유지보수, 테스트(특히 Mock 주입) 하기 훨씬 쉽다.

 

4. AOP, 트랜잭션, 보안

  • new 키워드로 생성한 객체는 순수 객체 → Spring 이 개입할 수 없다.
  • Bean 으로 등록하면 Spring Proxy 를 걸어서 AOP(로깅, 모니터링, 성능 측정)이나 @Transactional 같은 기능 적용 가능

5. 스코프 제어

  • 필요하다면 요청 단위(@RequestScope), 세션 단위(@SessionScope) Bean 으로 관리 가능.
  • new 로는 불가능.

 

예시

1. new 로 직접 객체 생성

public class MyService {
	private final MyRepository myRepository;
    private final Logger logger;
    
    // MyService 가 동작하려면 MyRepository 가 필요함
    public MyService(MyRepository myRepository, Logger logger) {
        this.myRepository = myRepository;
        this.logger = logger;
    }
    
    public void doSomething() {
        System.out.println("작업 실행!");
        // DB 조회
        String data = myRepository.findData();
        System.out.println("조회된 데이터 = " + data);
    }
}

public class MyController {
    private final MyService myService;

    // 직접 new 해서 생성
    public MyController() {
    	MyRepository repo = new MyRepository();
        Logger logger = Logger.getLogger("myLogger");
        this.myService = new MyService(repo, logger);
    }

    public void handleRequest() {
        myService.doSomething();
    }
}

 

➡️ 문제점

  • MyController 안에서 MyService 를 직접 생성(new) → 강한 결합
  • MyService 가 DB, Logger 등 다른 객체를 필요로 하면, 전부 new 키워드로 생성해줘야 한다.
  • 테스트할 때 MyService 대신 MockMyService 같은 걸 주입하기 힘들다.

위처럼 MyService 에 생성자 주입으로 MyRepository 나 Logger 가 있을 경우 MyController 에서는

new 키워드를 통해 MyRepository 나 Logger 를 생성하고 MyService 를 주입해줘야 한다.

 

 

2. Spring Bean 으로 등록해서 사용

@Service
public class MyService {
    private final MyRepository myRepository;
    private final Logger logger;
    
    // MyService 가 동작하려면 MyRepository 가 필요함
    public MyService(MyRepository myRepository, Logger logger) {
        this.myRepository = myRepository;
        this.logger = logger;
    }
    
    public void doSomething() {
        System.out.println("작업 실행!");
        // DB 조회
        String data = myRepository.findData();
        System.out.println("조회된 데이터 = " + data);
    }
}

@Controller
public class MyController {
    private final MyService myService;

    // Spring 이 자동으로 주입 (생성자 주입 권장)
    public MyController(MyService myService) {
        this.myService = myService;
    }

    public void handleRequest() {
        myService.doSomething();
    }
}

 

➡️ 장점

  • MyService 는 @Service 어노테이션으로 인해 Bean 으로 등록된다 → Spring 컨테이너가 싱글톤으로 관리
  • MyController 는 그냥 MyService 타입만 선언 → 실제 구현체는 Spring 이 주입
  • 나중에 MyService 를 MyServiceImpl ↔ MockMyService 로 교체해도 MyController 는 수정할 필요 없다.
    => MyController 에서는 MyService 라는 클래스 타입만 선언했기 때문에 상관없다.
  • 트랜잭션, AOP, 보안 같은 Spring 기능을 붙이려면 반드시 Bean 이어야 함

 

✅ 핵심 차이

  • new 키워드 생성 방식 : 객체 생명주기, 의존성 관리 → 개발자가 직접 책임
  • Bean 생성 방식 : 객체 관리, 주입, 기능 확장 → Spring 이 대신 책임

 

 

Spring IOC 컨테이너에 Spring Bean을 등록하는 방법

빈을 등록하는 방법은 다양하지만 크게 두가지 방법이 있다.

 

1. @ComponentScan 어노테이션을 사용한 Component Scanning

@ComponentScan 이란 @Component 어노테이션 및 streotype(@Service, @Repository, @Controlle) 등 어노테이션이 부여된 Class들을 자동으로 Scan하여 Bean으로 등록해주는 역할을 하는 어노테이션이다.

 

보통 Spring Boot 프레임워크를 사용하게되면 main 함수위에 사용한다.

 

위 그림을 예를 들자면 basePackages 옵션을 통해 com.angular.web의 package 하위에 존재하는 @Component 어노테이션 및 stereotype(@Service, @Repositofy, @Controller)  어노테이션이 부여된 Class들을 자동으로 Scan 하여 Bean 등록을 해준다.

 

위 그림과 같이 @Controller도 내부적으론 @Component 어노테이션을 사용한다. @Service, @Repository도 마찬가지

 

2. 빈 설정파일에 직접 빈 등록(@Configuration, @Bean)

직접 빈을 등록하기 위해선 @Configuration 및 @Bean 어노테이션을 사용한다.

라이브러리 혹은 내장 클래스 등 개발자가 직접 제어 불가능한 클래스의 경우 @Configuration 어노테이션과 @Bean 어노테이션을 사용하여 Bean으로 등록한다.

 

728x90
반응형

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

바이트 순서 표시(BOM, Byte Order Mark)  (0) 2021.12.02
RSA 암호화 만들기  (1) 2021.10.20
Spring Web Framework(IOC, DI)  (1) 2021.10.18
@Bean+@Configuration, @Component 어노테이션  (0) 2021.10.18
Spring Security  (0) 2021.08.28
Contents