ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] bean 라이프 사이클
    Programming/SpringBoot 2024. 5. 9. 11:29
    728x90

    Bean

    자바 어플리케이션의 객체들은 독립적으로 동작하는 것 보다 서로 상화작용하여 동작하는 경우가 많은데 이를 "객체의 의존성"이라고 표현한다.

    스프링에서는 스프링 컨테이너에 객체들을 생성하면 객체끼리 의존성을 주입(Dependency Injection)하는 역할을 한다.

    스프링 컨테이너에 등록한 객체들을 "빈"이라고 한다.

     

    스프링 컨테이너에 Bean을 등록하는 2가지 방법

    1. 컴포넌트 스캔과 자동 의존관계 설정

    2. 자바 코드로 직접 스프링 빈 등록

     

    1. 컴포넌트 스캔과 자동 의존관계 설정

    스프링 부트에서 사용자 클래스를 스프링 빈으로 등록하는 가장 쉬운 방법

    클래스 선언부 위에 @Component 어노테이션을 사용하는 것이다.

    @Controller, @Service, @Repository 모두 @Component를 포함하고 있으며 

    해당 어노테이션으로 등록된 클래스들은 스프링 컨테이너에 의해 자동으로 생성되어 스프링 빈으로 등록된다.

     

    2. 자바 코드로 직접 스트링 빈 등록

    수동으로 스프링 빈을 등록하려면 자바 설정 클래스를 만들어 사용해야 한다.

    @Configuration 어노테이션을 클래스 선언부 위에 추가하여 설정 클래스로 만든다.

    특정 타입을 리턴하는 메소드를 만들고, @Bean어노테이션을 붙여주면 자동으로 해당 타입읭 빈 객체가 생성됨

     

    @Bean 어노테이션의 주요 내용

    • @Configuration설정된 클래스의 메소드에서 사용 가능
    • 메소드의 리턴 객체가 스트링 빈 객체임을 선언함
    • 빈의 이름은 기본적으로 메소드의 이름
    • @Bean(name="name")으로 변경가능
    • @Scope를 통해 객체 생성(라이프사이클)을 설정할 수 있음
    • @Component어노테이션을 통해 @Configuration없이도 빈 객체를 생성할 수도 있음
    • 빈 객체에 init(), destory() 등 라이프사이클 메소드를 추가한 다음 @Bean에서 지정할 수 있음

     

    등록된 Bean 사용하기

    의존성 주입은 필요한 객체를 직접 생성하는 것이 아닌 외부로부터 객체를 받아서 사용하는 것이다.

    이를 통해 객체간의 결합도를 줄이고 코드의 재활용성을 높일 수 있다.

     

    의존성을 주입해야 하는 이유

    • Test가 용이해진다.
    • 코드의 재사용성을 높여준다
    • 객체 간의 의존성을 줄이거나 없앨 수 있다
    • 객체 간의 결합도를 낮추면서 유연한 코드를 작성할 수 있다

    의존성 주입의 3가지 방법

    1. 생성자 주입(Constructor Injection)

    2. 필드 주입(Field Injection)

    3. 수정자 주입(Setter Injection)

     

    1. 생성자 주입

    @Controller
    @RequiredArgsConstructor
    public class MemberController {
        private final MemberService memberService;
        ...
    }

     

    2. 필드 주입

    @Controller
    public class MemberController {
        @Autowired
        private MemberService memberService;
        ...
     }

    필드에 @Autowired 어노테이션만 붙여주면 자동으로 의존성 주입

     

    단점

    - 코드가 간결하지만, 외부에서 변경하기 힘들다. 

      프로그램이 복잡해지면 어떤 의존 관계들이 있는지 파악하기 어렵다.

    - 프레임워크에 의존적이고 객체지향적으로 좋지 않다.

     

    3. 수정자 주입

    @Controller
    public class MemberController {
    	private MemberService memberService;
        
        @Autowired
        public void setMemberService(MemberService memberService){
        	this.memberService = memberService;
        }
        ...
     }

    setter메소드에 @Autowired어노테이션을 붙이는 방법이다.

     

    단점

    - 수정자 주입을 사용하면 setXXX메소드를 public으로 열어두어야 하기 때문에 어디서든 변경이 가능하다.

     

     

    3가지 방식 중 생성자 주입을 권장한다.

    테스트에 용이하고, 어떤 의존 관계를 가지고 있는지 파악할 수 있다.

     

    권장하는 이유 중에 "불변성"을 적어놓은 블로그들이 많은데

    이는 잘못된 내용이다.

     

    생성자로 의존성을 주입할 때 final로 선언한다고 객체가 변하지 않을까? 다시 말해 final은 불변성을 보장하는가?

    ArrayList를 예를 들어보자. 

    ArrayList를 final로 선언하게 되면 ArrayList를 담고 있는 객체는 불변할지 몰라도 ArrayList안에 담기는 요소들은 변할 수 있다!!

    -> 객체 안의 필드는 불변성을 보장하지 않는다!

    그렇기 때문에 final로 불변성이 보장된다고 하면 안된다.

     


    스프링 컨테이너의 이해와 활용

    스프링의 IoC컨테이너는 Bean객체들을 책임지고 의존성을 관리한다.

    객체들을 관리한다는 것은 객체의 생성부터 소멸까지의 생명주기 관리를 개발자가 아닌 컨테이너가 해준다는 말이다.

    객체 관리의 주체가 프레임워크(container)가 되기 때문에 개발자는 로직에 집중할 수 있다는 장점이 있다.

     

    스프링 컨테이너는 BeanFactory와 ApplicationContext 두 가지 주요 인터페이스로 구성된다.

    BeanFactory는 스프링 빈의 기본적인 관리 기능을 제공하고,

    ApplicationContext는 BeanFactory의 모든 기능을 상속받아 이벤트 발행 등 더욱 확장된 기능을 제공한다.

    왜냐하면 스프링 컨테이너는 애플리케이션의 라이프사이클을 관리하고, 빈의 생성부터 소멸까지 전 과정을 제어하기 때문이다. 

    따라서 스프링 컨테이너의 이해는 스프링 기반 애플리케이션 개발의 핵심이다.

     

    스프링 컨테이너가 생성될 때 객체(Bean)를 생성하고 의존성을 주입하는데, 의존관계 주입 후 Bean을 초기화하고, 스프링 컨테이너를 종료하기 전에 객체를 소멸시켜야 한다.

     

    객체를 초기화 한다는 것은, 객체 생성 이외에 외부 커넥션을 연결하거나, 초기값을 등록하는 등의 여러 작업을 말한다.

    이 과정을 생성자서 진행해도 되지만, 객체 생성에 비해 초기화는 비교적 무거운 일을 수행하기 때문에 객체를 생성하는 부분과 초기화하는 부분을 명확하게 나누는 것이 좋다.

     

    Bean LifeCycle

    스프링 컨테이너 생성 -> Bean생성 -> 의존성 주입 -> 초기화 콜백 -> Bean사용 -> 소멸 전 콜백 -> 스프링 종료

     

    초기화 콜백(init)

    Bean이 생성되고, Bean의 의존성 주입이 완료된 뒤 호출됨

     

    소멸 전 콜백(destory)

    스프링이 종료되기 전, Bean이 소멸되기 직전에 호출됨

     

    스프링에서 Bean의 생명주기는 크게 3단계로 볼 수 있다.

    1. Bean의 인스턴스 생성 단계

    2. Bean의 의존성 주입(Dependency Injection)

    3. Bean의 초기화(Initialization)과 소멸(Destruction)단계

     

    Bean의 인스턴스 생성 단계

    bean은 스프링 컨테이너에서 빈으로 등록되면, 해당 빈의 클래스의 인스턴스를 생성한다.

    이 떄, 스프링 컨테이너는 Bean의 클래스를 찾아서 인스턴스를 생성한다.

     

    Bean의 의존성 주입 단계

    Bean의 생성이 완료되면, 해당 bean이 의존하는 다른 Bean들이 주입된다. 이 때, 스프링은 설정 파일에서 빈 간의 의존관계를 확인하고, 해당 빈이 의존하는 다른 빈을 찾아서 주입한다.

     

    Bean의 초기화와 소멸 단계

    Bean의 인스턴스 생성과 의존성 주입이 완료된 후에는, 스프링 컨테이너는 빈을 초기화하고, 필요에 따라 소멸한다.

    빈의 초기화 작업은 InitializaingBean인터페이스의 afterPropertiesSet()메서드나, @PostConstruct어노테이션을 이용하여 구현할 수 있다.

    빈의 소멸 작업은 DisposableBean인터페이스의 destory()메서드나, @PreDestory어노테이션을 이용하여 구현할 수 있다.

     

    이처럼, 스프링 Bean의 생명주기는 빈의 인스턴스 생성, 의존성 주입, 초기화, 소멸 과정으로 이루어진다. 스프링은 이러한 빈의 생명주기를 관리하여 Bean이 애플리케이션에서 적절하게 사용될 수 있도록 한다.

     

    스프링 Bean의 생명주기는 객체 생성, 초기화, 사용 및 소멸로 구성된다. 스프링은 Bean이 생성될 때 적절한 초기화 메서드를 호출하고, Bean을 소멸하기 전에 적절한 종료 메서드를 호출한다. 

    스프링은 bean의 스코프에 따라 다른 생명주기를 가지고, Singleton, Prototype등의 스코프가 있다.

     

    콜백 설정

    @PostConstruct 

    @PreDestory

    스프링에서 권장하는 방법으로, 어노테이션을 초기화, 소멸 전 콜백 메소드에 붙여주면 된다.

    Spring에 종속적인 기술이 아니고, Java표준 기술이다.

     

    @Component를 이용하여 Bean을 등록하는 경우에는 하나의 클래스에서 확인할 수 있다는 장점도 있다.

     

     

     

     

     

    참고

     

    https://dev-coco.tistory.com/170

     

    https://www.inflearn.com/blogs/3313

     

    https://f-lab.kr/insight/spring-container-and-bean-lifecycle-management

     

     

     

     

     

     

    728x90

    'Programming > SpringBoot' 카테고리의 다른 글

    [Spring] 테스트 코드  (0) 2024.05.14
    [Spring] dataSource or dataSourceClassName or jdbcUrl is required.  (0) 2024.05.11
    [Network] Proxy, Reverse Proxy  (0) 2024.04.03
    [CS] 웹 서비스 구조  (0) 2024.03.27
    [Spring] IntelliJ JSP  (0) 2024.03.25

    댓글

© 2022. code-space ALL RIGHTS RESERVED.