코코코딩공부/Spring

[Spring] Bean 이란 ?

Ocean_ 2023. 4. 23. 11:03

들어가며

스프링을 사용하면서 기존 자바보다 객체 생성, 조립, 사용을 훨씬 편하게 해준다는 것을 알았고 이에 기본적으로 Bean이라는 개념이 사용된다는 것을 알았다. 하지만 Bean이 무엇인지에 대한 의문점이 있어 정리해보았다.


스프링 빈 이란 ?

빈이란 스프링 IOC 컨테이너 가 관리하는 객체이다.

빈은 Spring IoC 컨테이너에 의해 인스턴스화, 조립 및 관리되는 객체이다.

인스턴스화 된 빈은 @Autowired를 통해 의존성 주입을 받을 수 있다.

인텔리제이에서 옆에 콩처럼 표시가 되어있다면 빈등록이 되었다는 것을 의미한다.

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

}

빈을 사용하는 이유 ?

의존성 주입에 있어서 용이하다. 싱글톤 객체를 사용함으로써 객체를 관리하기가 용이하다.

 

빈과 자바 객체의 차이점은 ?

Bean은 Spring IoC 컨테이너에 의해 관리되며, 자바 객체는 Ioc 컨테이너가 관리하지 않는 객체도 포함이다.


스프링 IOC 컨테이너 란 ?

IOC 라는 것은 제어의 역전 객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것. 의존관계, 생명주기 등 제어 하는 것이 역전되었다.

 

컨테이너는 객체의 생명주기 관리 및 생성된 인스턴스 관리하는 것을 의미한다.

 

이는 직접적으로 의존성을 만들지 않고, 외부에서 의존성을 가져온다고 이해할 수 있다. 제어의 역전이라는 말은 객체를 생성하고 관리하는 역할을 모두 스프링에게 위임하기에 표현된다. bean들의 생명주기를 관리할 수 있다.

 

스프링을 하나의 ioc컨테이너라고한다. 스프링 컨테이너는 DI라는 방식으로 객체를 외부에서 주입받아 생성하고 관리한다. 스프링 컨테이너를 빈을 생성하는측면에서 빈팩토리, 스프링컨테이너, ioc컨테이너 DI컨테이너 등등으로 사용한다.

 

왜 사용 할까?

객체간의 의존성을 낮추기 위해 사용한다.

스프링 컨테이너에서 싱글톤 컨테이너 역할을 해줌으로써 싱글톤 패턴의 단점을 없애고 객체의 단일성을 유지할 수 있다.

그렇기에 각각의 빈들은 싱글톤 패턴 적용을 위한 코드를 작성할 필요가 없다. 더하여 DIP, OCP, 테스트, private 생성자를 고민하지 않아도 된다.

 

어떻게 동작할까 ?

ApplicationContext는 beanFactory를 포함한 다양한 기능을 하는 인터페이스를 상속한다.

beanFactory보다는 더 많은 기능을 할 수 있는 ApplicationContext를 자주 사용한다.

둘의 차이점은 빈 생성 시기에 있다.

ApplicationContext는 애플리케이션 실행 시 빈을 로딩한다.

beanFactory는 애플리케이션 실행 중 빈을 사용 시 빈을 로딩한다.

 

왜 이런 차이가 있을까 ?

자주 사용되지 않는 빈을 계속 ioc컨테이너에 두고 있을 필요가 없다. 자원을 아끼기 위해 실제 빈을 사용할 경우에만 로딩하며, 자주 사용될 경우 컨테이너에 올려놓고 사용하면 좋기 때문이다.

스프링 컨테이너 빈 생명주기

  1. 스프링 컨테이너가 생성된다.
  2. 스프링 빈을 생성한다.
  3. 의존 관계를 주입한다.
  4. 초기화 콜백 메세지 호출
  5. 빈 사용 및 호출
  6. 소멸 콜백 메세지 호출
  7. 스프링 종료

자바 빈 등록은 어떻게 하나 ?

어노테이션 이용

@~ 와 같은 기능을 어노테이션이라고한다. 이런 어노테이션은 코드에 추가되면 메타데이터로써 특별한 기능을 수행할 수 있다.

빈 등록을 위해서는 @Component 어노테이션을 이용해 스프링이 확인하고 자체적으로 빈을 등록시킨다.

@Service, @Controller, @Repository와 같은 어노테이션도 빈 등록이 가능한데 아래와 같이 선언이 되어있기에 사용 가능하다.

 

Bean Configuration 이용

아래와 같이 Configuration file에 직접 Bean을 등록 할 수 있다.

@Configuration
public class Config {
    @Bean
    public Controller Controller() {
        return new Controller;
    }
}

빈이름은 메소드 이름을 사용한다. 직접 부여도 가능하다.

빈이름은 항상 다른이름을 부여해야함. 같으면 무시되거나 기존 빈을 덮어버리거나 오류발생한다.

 


빈 스코프란 ?

말 그대로 스프링 빈이 사용되어지는 범위이다. 스프링 빈이 애플리케이션이 작동되는 동안 어떻게 사용할 것인지에 대해 결정하는 것이다. 기본적으로 SingleTon으로 작동한다.

 

singleton - 앱이 구동되는 동안 하나만 사용

스프링 컨테이너 생성 시점에 초기화 메소드가 실행된다.

@Scope("singleton")
    static class SingleTon{
    }

    @Test
    void singleTon_Test(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(SingleTon.class);
        SingleTon singleTon1 = ac.getBean(SingleTon.class);
        SingleTon singleTon2 = ac.getBean(SingleTon.class);
        System.out.println("singleTon1 = " + singleTon1);
        System.out.println("singleTon2 = " + singleTon2);
        Assertions.assertThat(singleTon1).isEqualTo(singleTon2);
    }

 

prototype - 매번 새로운 빈을 사용

스프링 컨테이너에서 빈을 조회할 때 생성되고 초기화한다.

매번 사용할 때마다 의존관계 주입이 완료된 새로운 객체가 필요할 때 쓰면된다. 하지만 잘 안쓴다.

@Scope("prototype")
    static class ProtoType{
    }
    @Test
    void protoType_Test(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(ProtoType.class);
        ProtoType protoType1 = ac.getBean(ProtoType.class);
        ProtoType protoType2 = ac.getBean(ProtoType.class);
        System.out.println("protoType1 = " + protoType1);
        System.out.println("protoType2 = " + protoType2);
        Assertions.assertThat(protoType1).isNotEqualTo(protoType2);
    }

 

reqeust - http request 라이프사이클 마다 사용

동시에 여러 http요청이 오면 어떤 요청인지 구별하기 힘든데 이 때 구별하기에 좋다.

http 요청 당 하나씩 생성되고 요청이 끝나는 시점에 소멸된다.

@Component
@Scope(value = "request")
public class request {
}

session - http session 라이프사이클 마다 사용

application - ServletContext라이프 사이클 마다 사용

websocket - Websocket 라이프 사이클 마다 사용

singleTon 빈 안에서 prototype 빈을 사용해도 된다.