본문 바로가기

카테고리 없음

스프링부트 스타터를 구성해보자

이전에 스프링 부트로 작업한 적이 있다면 다양한 스타터가 있다는 것을 알고 있습니다. 이 스타터는 더 이상 필요하지 않도록 모든 종류의 것들을 자동으로 구성합니다. 이렇게 하면 더 빨리 시작할 수 있으며 일반적으로 다른 항목에서 복사하여 붙여넣는 구성에 대해 신경 쓰지 않아도 됩니다. 좋은 점은 이미 나와 있는 Spring 부트 스타터에 국한되지 않는다는 것입니다. 자신만의 스타터도 작성할 수 있기 때문입니다.

 

시작하기

여기서는 Spring Initializr를 사용하지 않고 간단한 Java/Maven 프로젝트를 생성하겠습니다. 그런 다음 우리가 할 첫 번째 일은 종속성 관리에 spring-boot-dependencies를 추가하는 것입니다.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

이를 통해 전체 스타터/BOM을 가져오지 않고 스스로 버전 번호를 제공하지 않고도 원하는 Spring 종속성을 사용할 수 있습니다.

 

다음 단계는 다음 두 가지 종속성을 추가하는 것입니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

첫 번째 종속성을 사용하면 적절한 주석을 사용하여 자체(조건부) 구성 클래스를 생성할 수 있고, 두 번째 종속성을 사용하면 구성 속성에 대한 적절한 메타데이터를 생성할 수 있으므로 IDE가 인텔리센스에서 선택할 수 있습니다.

 

이 튜토리얼에서는 이전에 이야기한 모니터링을 위한 Prometheus 엔드포인트를 제공하는 스타터를 작성하겠습니다. 이를 위해 simpleclient_spring_boot, simpleclient_hotspot, simpleclient_servlet, javax.servlet-api 및 commons-lang3 종속성을 추가할 것입니다.

 

Configuration properties(구성 속성)

Spring 부트의 필수 부분을 생각할 때 아마도 응용 프로그램 속성에 대해 생각할 것입니다. 자신의 Spring 부트 스타터를 작성할 때 구성 가능하게 만들고 싶을 것입니다. 이렇게 하려면 고유한 클래스를 만들고 @ConfigurationProperties로 주석을 달 수 있습니다. 제 경우에는 다음과 같이 모니터링 라이브러리를 구성할 수 있기를 원합니다.

monitoring:
  path: /prometheus
  interval: 10000
  matchers:
    - name: api.user
      method: GET
      matcher: /api/user
    - name: api.token
      method: GET
      matcher: /api/token
    - name: prometheus
      method: GET
      matcher: /prometheus
    - name: metrics
      method: GET
      matcher: /metrics
내가 만든 클래스는 다음과 같습니다.
@ConfigurationProperties("monitoring")
public class MonitoringProperties {
    private String path = "/prometheus";
    private int interval = 10;
    private List<MonitoringPathMatcher> matchers;

    // Getters + Setters ...
}
public class MonitoringPathMatcher {
    private static final AntPathMatcher MATCHER = new AntPathMatcher();
    private String name;
    private HttpMethod method;
    private String matcher;

    // Getters + Setters + Equals + Hashcode

    public boolean isMatching(HttpServletRequest request) {
        return getMethod().matches(request.getMethod()) && MATCHER.match(getMatcher(), request.getServletPath());
    }
}

@ConfigurationProperties는 이 POJO가 모니터링 접두사가 붙은 모든 구성 속성에 사용됨을 나타냅니다. 반면에 속성 이름은 POJO에서와 같은 이름을 가져야 합니다. 따라서 이 경우 Monitoring.path는 MonitoringProperties 클래스의 경로 속성과 일치합니다.

 

속성 이름에 camelcase를 사용하는 경우 Monitoring.camelCase=... 또는 monitoring.camel-case=...를 사용하여 일치시킬 수 있습니다.

 

라이브러리의 유용성을 향상시키기 위해 구성 속성의 속성에 주석을 추가할 수 있습니다. 예를 들면 다음과 같습니다.

/**
 * Path of the Prometheus metrics endpoint
 */
private String path = "/prometheus";

spring-boot-configuration-processor 종속성을 사용한 경우 이러한 주석을 메타데이터로 사용합니다. 이렇게 하면 IDE에서 선택하여 개발자에게 보여줄 수 있습니다. IntelliJ의 경우 다음과 같습니다.

나만의 자동 구성 생성하기

다음 단계는 고유한 자동 구성 클래스를 만드는 것입니다. 이렇게 하려면 다음과 같이 간단한 클래스를 만들고 @Configuration 주석으로 주석을 추가하는 것으로 시작합니다.

@Configuration
public class MonitorAutoConfiguration {
    // ...
}

그런 다음 @EnableConfigurationProperties 주석을 추가하여 이전에 만든 구성 속성을 활성화해야 합니다. 예를 들어:

@Configuration
@EnableConfigurationProperties(MonitoringProperties.class)
public class MonitorAutoConfiguration {
    // ...
}

이제 Spring이 자동 구성을 호출하도록 할 때 사용자 정의할 수도 있습니다. 우리의 경우 모니터링 라이브러리이기 때문에 Spring 부트 액추에이터의 메트릭 저장소 자동 구성이 로드된 후 이를 호출하려고 합니다. 이를 위해 @AutoConfigureAfter 주석을 사용할 수 있습니다.

@Configuration
@EnableConfigurationProperties(MonitoringProperties.class)
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class)
public class MonitorAutoConfiguration {
    // ...
}

Conditionals(조건부 사항)

이제 일부 Spring 부트 스타터는 특정 종속성 또는 기타 사항이 충족될 때만 호출됩니다. 예를 들어 JPA 자동 구성은 드라이버가 클래스 경로에 있을 때만 트리거되는 반면 일부 자동 구성은 특정 속성이 설정된 경우에만 트리거됩니다.

 

우리의 경우 GaugeService와 CounterService 클래스가 모두 클래스 경로에 있는지 확인하고 싶습니다. @ConditionalOnClass 주석을 추가하여 이를 수행할 수 있습니다. 또한 프로젝트가 웹 애플리케이션인 경우에만 자동 구성을 호출하려고 합니다. 프로젝트가 웹 응용 프로그램이 아니면 Prometheus 끝점으로 아무 것도 할 수 없으므로 라이브러리로도 모니터링할 수 없습니다. 이렇게 하려면 @ConditionalOnWebApplication 주석을 사용할 수 있습니다.

@Configuration
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class)
@ConditionalOnWebApplication
@ConditionalOnClass(name = {"org.springframework.boot.actuate.metrics.CounterService", "org.springframework.boot.actuate.metrics.GaugeService"})
@EnableConfigurationProperties(MonitoringProperties.class)
public class MonitorAutoConfiguration {
    // ...
}

@ConditionalOnClass 주석의 좋은 점은 클래스를 문자열로 제공할 수 있다는 것입니다. 그래서 어떻게든 클래스 경로에 해당 클래스를 추가할 필요가 없습니다.

 

이제 구성 클래스에 적절하게 주석을 달았으므로 자동 구성이 작동하는 데 필요한 빈을 추가할 수 있습니다. 제 경우에는 특정 경로를 모니터링하는 필터가 필요하고 자동으로 생성하도록 Prometheus 클라이언트 구성을 설정해야 합니다.

@Bean
public SpringBootMetricsCollector springBootMetricsCollector(Collection<PublicMetrics> publicMetrics) {
    SpringBootMetricsCollector springBootMetricsCollector = new SpringBootMetricsCollector(publicMetrics);
    springBootMetricsCollector.register();
    return springBootMetricsCollector;
}

@Bean
public ServletRegistrationBean servletRegistrationBean(MonitoringProperties properties) {
    DefaultExports.initialize();
    return new ServletRegistrationBean(new MetricsServlet(), properties.getPath());
}

@Bean
public MonitoringFilter filter(CounterService counterService, GaugeService gaugeService, MonitoringProperties monitoringProperties) {
    return new MonitoringFilter(counterService, gaugeService, monitoringProperties);
}

여기에서 우리가 만든 필터와 ServletRegistrationBean에서 MonitoringProperties를 사용하여 /prometheus 끝점을 만든 것을 볼 수 있습니다.

 

마지막

Spring 부트 스타터를 다른 프로젝트에 포함하기 전에 한 가지 더 해야 합니다. 애플리케이션이 Spring 부트 스타터를 선택하도록 하려면 spring.factories라는 특수 속성 파일을 생성해야 합니다. 이 파일은 src/main/resources/META-INF 폴더 내에 있어야 하며 org.springframework.boot.autoconfigure.EnableAutoConfiguration 속성을 포함해야 합니다. 예를 들면 다음과 같습니다.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=be.g00glen00b.monitor.MonitorAutoConfiguration

이 속성은 자동 구성 클래스의 정규화된 이름을 포함해야 합니다. 이 경우에는 be.g00glen00b.monitor.MonitorAutoConfiguration이었습니다.

 

이제 완료했으므로 라이브러리를 종속성으로 정의하여 다른 프로젝트에 라이브러리를 포함할 준비가 되었습니다. 그렇게 하면 자동 구성이 자동으로 호출되고(모든 조건이 충족되는 경우) 모든 빈이 생성됩니다.