본문 바로가기

강의/토비의 스프링부트

자동 구성 기반 애플리케이션 (meta annotation, composed annotation)

 

@AutoConfiguraiton

 

Meta annotation에 대해서 살펴보자

여기서 Meta annotation이란 Controoler Service annotation을 말하는 것이다.

 

 

Meta annotation을 활용하면 좋은점

Component를 붙이는 것과 @Controller를 붙이

WebMvc의 controller 역할을 하는 구나

buisiness를 담당하는 중요 로직이 들어있구나 라는 것을 알 수 있음

 

부가 기능을 넣을 수 있음

Dispatcher servlet이 Web controller로 사용되어 지는 구나

annotation을 이용한 mapping 정보가 들어있구나

request mapping, get mapping을 살펴볼 것임

 

annotation 기능을 확장 가능

 

meta annotation이라는 것을 상속이라는 개념과 혼동하면 안됨

annotation 자체는 상속이라는 개념이 없음

 

annotation에는 retention과 target을 꼭 줘야하는데

target이 중요한 이유는 annotation이 적용될 수 있는 위치가 굉장히 많음

그중에서 annotation type이라는 위치에 사용하여야만 meta annotation으로 사용될 수 있다.

 

spring에서 meta annotation이

Junit5 annotation을 살펴보

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@UnitTest
@interface FastUnitTest {

}

@Retention(RetentionPolicy.RUNTIME)
// annotation type으로 지정을 하였기 때문에 위에 meta annotation을 만들 때 또 사용할 수 있다.
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Test
@interface UnitTest {

}

 

합성 애노테이션(Composed-annotation)

meta annotation을 하나 이상 적용해서 만드는 경우를 말한다.

합성 어노테이션을 사용하면

 

어노테이션이 좋다고 해서 많이 쓰는데

코드가 지저분해 질 때도 있다.

반복적으로 조합이 많이 사용된다고 하면 합성 어노테이션 형태로 만들어서 간략하게 사용할 수 있다.

 

@Configuration : meta annotation으로 component를 가지고 있다.

 

 

지금까지 우리가 만들었던 bean이다.

HelloServer 의 기능을 제공하기 위해 만ㄷ르었던 클래스를 빈으로 등록 (3개)

스프링 부트가 컨테이너 리스를 지원하기 위해서

내장형 서블릿 컨테이너 를 이용하는 독립 실행형 애플리케이션 방식으로 동작을 하면서 요구되어지는 두개의 빈이 있다.

 

이것을 어떻게 구분해서 구성정보를 어떤 전략으로 작성을 할 것인가를 생각해 볼 것인데

우선 스프링 컨테이너에 올라가는 빈들을 구분하는 방법을 살펴볼 것이다.

 

이것은 예로 여러가지 빈을 나열해 보았다.

 

 

스프링 컨테이너가 관리하는 빈들은 컨테이너 인프라스트럭처 빈과 애플리케이션 빈으로 나눠진다.

 

애플리케이션 빈

개발자가 어떤 빈을 사용하겟다고 명시적으로 구성정보를 제공한 것

그렇게 제공된 컨피규레이션 메타 데이터를 이용해서 스프링 컨테이너가 등록해주는 것들을 말함

 

컨테이너 인프라스트럭처 빈

스프링 컨테이너 자신이거나

스프링 컨테이너가 기능을 확장하면서 추가해온 것들을 빈으로 등록시켜서 사용하는 것들

이러한 종류의 빈들은 우리가 등록해달라고 요청하지 않지만

컨테이너가 스스로 빈으로 등록해서 동작하는 방식으로 이용을 한다.

 

컨테이너는 자기 자신도 빈으로 접근할 수 있도록 등록을 하고

외부 설정과 같은 환경 정보에 접근할 때 사용하는 environment 빈도 존재하고

그리고 스프링 컨테이너가 하는 굉장히 중요한 일이 빈 오브젝트를 생성, 초기화, 관계를 맺고, 라이프 사이클을 관리하는 것인데

이렇게 컨테이너가 빈을 만들고 다루는 작업중에 기능을 추가하는 방법들이 있는데

그것이 BeanPostProcessor, BeanFactoryPostProcessor 라는 것들이 있는데 이런것들도 빈으로 등록한다.

이런것들은 스프링 컨테이너의 기능이다.

 

우측에 있는 것은 일반적으로 우리의 관심사가 아니고

일반적으로 애플리케이션에서는 참조하지 않는다. (활용할 수는 있다.)

 

그런데 개발자가 구성정보를 제공해야하는 애플리케이션 빈도

구분을 할 수 있다.

 

2가지 종류로 구분 가능

 

애플리케이션 로직 빈, 애플리케이션 인프라스트럭처 빈

아까 컨테이너 내부에서 기반 기능을 제공하는 컨테이너 인프라스트럭처 빈이 있다고 말햇는데

애플리케이션도 동일하게 구분할 수 있다.

 

애플리케이션 로직 빈

애플리케이션 기능, 비지니스 로직, 도메인 로직 이런 것들을 담고 있는

애플리케이션을 개발할 때 그런 코드들로 만들어진 빈

 

애플리케이션 인프라스트럭처 빈

기술과 관련된 것

대부분 우리가 작성하진 않고, 이미 만들어진 것들을 이 애플리케이션에서는 사용하겠다고 

빈 구성정보를 작성해야, 어플리케이션이 정상적으로 동작할 수 있도록 사용할 수 있다.

 

애플리케이션 로직 빈이 애플리케이션 인프라스트럭처 빈을 직접 참조해서 사용하기도 하고

스프링 메커니즘에 의해서 적절히 수행되기도 한다.

 

어쨋든 구성정보를 제공해야 등록된다.

 

일단 컨테이너 관련빈은 관심을 끄고

 

애플리케이션 빈 두가지를 자세히 생각해보자

 

 

우리가 만든 빈 다섯가지가 있었는데

틀에다가 넣어보려고 한다.

 

 

TomcatServletWebServerFactory, DispatcherServlet도 우리가 빈으로 등록해서 동작하고 잇고

이걸 빼면 어플리케이션이 동작을 안한다.

 

스프링 어플리케이션이 독립 실행형 어플리케이션으로 동작하려면 꼭 필요하다.

Dispatcher servlet은 spring mvc를 사용하면 필요하긴 하지만

직접 컨테이너에 서블릿으로 등록해서 사용햇고

톰켓서블릿웹서버팩토리는 임베디드 서블릿 컨테이너를 우리가 독립 실행형 어플리케이션에서 사용하기 때문에 필요했던 건데

기존 스프링 부트를 사용하기 전에는 이것을 빈으로 등록할 생각도 못했다

스프링 부트 어플리케이션에서는 이걸 꼭 빈으로 등록해야하고

정상적으로 동작하는데 필요하다.

 

이것을 애플리케이션 인프라스트럭처 빈이라고 부를수 있겠다.

 

 

좌측에 어플리케이션 로직을 담고 있는 빈은

사용자 구성정보를 담고있는 빈이라고 보면 되고

 

우측에 나오는 빈들은

나중에 db를 사용하거나 transactional manager 같은 빈들은

자동 구성정보로 구성정보가 만들어질 때 사용하는 빈이라고 보면 된다.

 

구성정보를 어떤 방식으로 만드느냐를 설명하는데

사용자 구성정보라는 것은 컴포넌트 스캔을 이용해서 자동으로 자바와 어노테이션을 통해서 구성정보를 읽어오는 방식이고

우측 빈들은 자동 구성정보 메카니즘을 통해 등록이 된다.

 

 

자동 구성정보가 적용되는 방식은 기본적으로

어플리케이션에서 사용될 수 있는 인프라스트럭처 빈들을 담은 컨피규레이션 클래스를 만들어 놓는다.

기능으로 구분을 하는 것

서블릿 컨테이너를 생성할 때 필요한 팩토리 빈들을 담고있는 구성정보와 

스프링 웹을 사용하기 위해서 필요한 디스패처 서블릿 빈들을 생성하는

컨피규레이션을 따로 구성하고

스프링 부트가

애플리케이션 필요에 따라서 이중에서 필요한 컨피규레이션들을 골라서

필요한 방식으로 구성을 해서 자동으로 적용을 해준다.

 

이것이 자동 구성정보 방식에 동작 방식인데 이해하기가 복잡하다.

그래서 지금까지 우리가 만든 두개의 인프라스트럭처 빈이지만

일단 여기에 자동구성정보를 이용한 오토 컨피규레이션 방식을 적용해 볼 것이다.

 

아래 구성정보는 사용자 구성정보가 아닌 자동 구성정보를 통해 등록이 되도록 수정해보자.

폴더를 옮겨주자 (자동으로 등록되지 않도록)

@Configuration
public class Config {
    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }
}

 

 

@Component 어노테이션이나 그걸 meta annotation으로 가지고 있는 클래스들을

클래스 이름으로 지정해주면 구성정보에 직접 추가해 줄 수 있다.

클래스 정보를 넘겨주면 구성정보에 추가가 된다.

 

package com.example.tobyboot.toby;

import com.example.config.Config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
// type : class, interface, enum을 대상으로 부여
@Target(ElementType.TYPE)
@Configuration
@ComponentScan
@Import(Config.class)
public @interface MySpringBootApplication {
}

 

Config 클래스를 외부로 옮겨서 ComponentScan을 통해 bean으로 등록되지 않도록

파일을 이동시켜주자

아래 그림에서 외부라고 표시된 곳으로 파일을 옮겨주면 된다.

 

Config 클래스 안에 집어넣은 빈들을 분리할 것이다.

Auot Configuration이라는 것은 미리 준비해둔 Configuration들을 스프링 부트가 어떤 것이 필요한 지를 판단하고 자동으로 선택해서 사용하게 해주는 것이다.

 

Import annotation 

최상단 어노테이션이 

@Retention(RetentionPolicy.RUNTIME)
// type : class, interface, enum을 대상으로 부여
@Target(ElementType.TYPE)
@Configuration
@ComponentScan
@Import({DispatcherServletConfig.class, TomcatWebServerConfig.class})
public @interface MySpringBootApplication {
}

 

정리

처음 구조이다.

configuration과 bean 어노테이션 조합으로 TomcatWebServerconfig와 DispatcherServeltConfig를 관리하였다.

 

자동 구성 정보를 이용하여 config가 등록될 수 있도록 구조를 아래와 같이 개편하였다.

EnableAutoConfiguration 폴더를 만들고 이를 import annotation을 이용하여 빈으로 등록하였다.

 

import 어노테이션을 안에서 TomcatWebServerConfig와 DispatcherServletConfig가 하드코딩으로 빈으로 등록되어 있다. 이를 수정해보자.

 

 

'강의 > 토비의 스프링부트' 카테고리의 다른 글

자동 구성 애노테이션 적용  (0) 2023.02.23
동적인 자동 구성 정보 등록  (0) 2023.02.23
ㅇㄹㄴㅇ  (0) 2023.02.22
테스트 코드  (0) 2023.02.22
Bean의 생명주기 메소  (0) 2023.02.21