본문 바로가기

Study/Spring Boot

5. 애플리케이션 설정과 검사


오류를 식별할 때 동적이고 분산된 애플리케이션이 많아지면 아래 작업을 수행해야 함

 

  • 애플리케이션의 동적 설정과 재설정
  • 현재 설정과 출처의 확인과 결정
  • 애플리케이션 환경과 헬스 지표(health indicators)의 검사와 모니터링
  • 실행 중인 애플리케이션의 로깅 수준을 일시적으로 조정해 오류 원인 식별

스프링 부트에 내장된 설정 기능, 자동 설정 리포트와 함께

Spring Boot Actuator로 애플리케이션 환경 설정을 유연하게 동적으로 생성, 식별, 수정하는 방법

5.1 애플리케이션 설정

스프링 부트는 애플리케이션의 동적 설정, 재설정을 가능케 하는 메커니즘 제공

애플리케이션 실행 중에도 설정과 재설정이 가능

 

-> 스프링 Environment를 활용해 다음과 같은 모든 소스의 설정 요소를 관리

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config

 

Core Features

Spring Boot uses Commons Logging for all internal logging but leaves the underlying log implementation open. Default configurations are provided for Java Util Logging, Log4j2, and Logback. In each case, loggers are pre-configured to use console output with

docs.spring.io

5.1.1 @Value

@Value 어노테이션

- 설정(Configuration)을 코드에 녹이는 가장 간단한 접근방식

- 패턴 매칭과 SpEL(Spring Expression Language, 스프링 표현 언어)을 기반으로 구축되어 간단하고 강력함

- 맞춤설정 속성과 @Value를 함께 사용하면 한 속성값을 다른 속성값으로 파생하거나 설정할 수 있음 (속성중첩)

 

//application.properties
greeting-name=Dakota
greeting-coffee=${greeting-name} is drinking Cafe Cereza
@RestController
@RequestMapping("/greeting")
class GreetingController{
	@Value("${greeting-name: Mirage}")
	private String name;
	
	@Value("${greeting-coffee: ${greeting-name} is drinking Cafe Ganador}")
	private String coffee;
	
	@GetMapping
	String getGreeting() {
		return name;
	}
	
	@GetMapping("/coffee")
	String getNameAndCoffee() {
		return coffee;
	}
}

(오) greeting-name=Dakota 주석처리 했을 때
속성중첩

 

속성 파일에서 greeting-name과 greeting-coffee를 모두 어노테이션 처리하면, 속성값을 정의하는 환경 소스가 없게 됨

GreetingController빈을 초기화할 때 가져오는 greeting-coffee 속성 안에는 어노테이션 처리를 하기 때문에

정의되지 않은 greeting-name이 있어서 오류 발생

 

@Value("${greeting-coffee: ${greeting-name} is drinking Cafe Ganador}")
	private String coffee;
    //위의 greeting-name 부분 때문에....

 

application.properties에 정의되고 @Value 하나만 사용하는 속성에는 또 다른 제한이 있음

  •  IDE는 해당 속성을 애플리케이션이 사용한다고 인식하지 못함
  • 속성값이 문자열 형태로 참조돼서 코드에 직접적으로 연결되지 않기 때문 

→ 타입 세이프와 도구로 검증 가능한 메커니즘을 선택하는 편이 좋음

5.1.2 @ConfigurationProperties

@ConfigurationProperties로 속성을 정의하고 관련 속성을 그룹화해서, 도구로 검증 가능하고 타입 세이프한 방식으로 속성을 참조하고 사용

  • @Configuration은 설정 속성에서만 사용하도록 클래스를 설정함
    • 애플리케이션 환경에 포함하기 위해 추가 설정을 해야 함
    • @ConfigurationPropertiesScan 어노테이션을 기본 애플리케이션 클래스에 추가

 

어노테이션 프로세서로 메타데이터를 생성하기 위해서 IDE가 @ConfigurationProperties 클래스와 application.properties 파일에 정의된 관련 속성을 연결하도록 pom.xml에 아래 의존성 추가

 

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

 

@ConfigurationPropertiesScan 어노테이션 추가
application.properties도 바꿔주기 ^_^

 

@RestController
@RequestMapping("/greeting")
class GreetingController{
	private final Greeting greeting;
	
	public GreetingController(Greeting greeting) {
		this.greeting = greeting;
	}
	
	@GetMapping
	String getGreeting() {
		return greeting.getName();
	}
	
	@GetMapping("/coffee")
	String getNameAndCoffee() {
		return greeting.getCoffee();
	}
}

@ConfigurationProperties(prefix = "greeting") //greeting 속성에 사용할 앞자리 부호 지정
class Greeting{
	private String name;
	private String coffee;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCoffee() {
		return coffee;
	}
	public void setCoffee(String coffee) {
		this.coffee = coffee;
	}
}

5.1.3 잠재적 서드 파티 옵션

@ConfigurationProperties의 또 다른 유용한 기능 

서드파티 컴포넌트를 감싸고 해당 속성을 애플리케이션 환경에 통합하는 기능

 

• 컴포넌트를 스프링빈으로 인스턴스화

- @Configuration 어노테이션이 달린 클래스 내에서 직접 또는 메타 어노테이션을 통해 @Bean 어노테이션이 달린 메서드를 생성하는 방법

(+) @SpringBootApplication > @SpringBootConfiguration > @Configuration (포함관계)

 

@SpringBootApplication
@ConfigurationPropertiesScan
public class SburRestDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SburRestDemoApplication.class, args);
	}
	
	@Bean
	@ConfigurationProperties(prefix = "droid")
	Droid creatdDroid() {
		return new Droid();
	}
}

class Droid{
	private String id, description;
	
	public String getId() {
		return id;
	}
	
	public void setId(String id) {
		this.id = id;
	}
	
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}
}

@RestController
@RequestMapping("/droid")
class DroidController{
	private final Droid droid;
	
	public DroidController(Droid droid) {
		this.droid = droid;
	}
	
	@GetMapping
	Droid getDroid() {
		return droid;
	}
}

 

5.2 자동 설정 리포트  Autoconfiguration Report

자동 설정을 통해서 어떤 빈이 생성되거나 생성되지 않았으며, 어떤 조건으로 빈 생성 여부가 결정되는지 알 수 있는 방법

 

  • --debug 옵션으로 애플리케이션의 jar 파일 실행: java -jar bootapplication.jar --debug
  • JVM 매개변수로 애플리케이션의 jar 파일 실행: java -Ddebug=true -jar bootapplication.jar
  • 애플리케이션의 application.properties파일에 debug=true 추가

Positive match - '참'으로 평가되어 행동을 취하는 조건

Negative match - 스프링 부트의 자동 설정이 수행하지 않은 동작과 그 이유를 보여줌

5.3 액추에이터

: 작동시키는 것, 무언가를 움직이게 하거나 제어하는 기계장치 의미

  • HTTP 엔드포인트나JMX(Java Management Extensions)로 실행 중인 앱의 모니터링과 관리 기능 제공
  • 스프링 부트의 실제 제품 단계 수준 기능을 모두 포함하고 보여줌

pom.xml에 의존성 추가

 

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

 

 

액추에이터는 실행 중인 애플리케이션의 정보에 접근하고 이를 노출함

info는 애플리케이션 heardbeat와 그 밖의 OOTB(설정 없이도 즉시 사용 가능한 기본값)를 제공하는 빈 세트가 기본값으로 설정됨

 

포함된 엔드포인트 세트나 배제된 엔드포인트 세트가 있는 속성으로 액추에이터를 쉽게 설정할 수 있음

포함된 엔드포인트 선택, 다음 항목을 application.properties에 추가

 

management.endpoints.web.exposure.include=env,info,health

//보안 완전히 비활성화 한 경우
//management.endpoints.web.exposure.include= *

 

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/actuator",
            "templated": false
        },
        "beans": {
            "href": "http://localhost:8080/actuator/beans",
            "templated": false
        },
        "caches-cache": {
            "href": "http://localhost:8080/actuator/caches/{cache}",
            "templated": true
        },
        "caches": {
            "href": "http://localhost:8080/actuator/caches",
            "templated": false
        },
        "health-path": {
            "href": "http://localhost:8080/actuator/health/{*path}",
            "templated": true
        },
        "health": {
            "href": "http://localhost:8080/actuator/health",
            "templated": false
        },
        "info": {
            "href": "http://localhost:8080/actuator/info",
            "templated": false
        },
        "conditions": {
            "href": "http://localhost:8080/actuator/conditions",
            "templated": false
        },
        "configprops-prefix": {
            "href": "http://localhost:8080/actuator/configprops/{prefix}",
            "templated": true
        },
        "configprops": {
            "href": "http://localhost:8080/actuator/configprops",
            "templated": false
        },
        "env-toMatch": {
            "href": "http://localhost:8080/actuator/env/{toMatch}",
            "templated": true
        },
        "env": {
            "href": "http://localhost:8080/actuator/env",
            "templated": false
        },
        "loggers": {
            "href": "http://localhost:8080/actuator/loggers",
            "templated": false
        },
        "loggers-name": {
            "href": "http://localhost:8080/actuator/loggers/{name}",
            "templated": true
        },
        "heapdump": {
            "href": "http://localhost:8080/actuator/heapdump",
            "templated": false
        },
        "threaddump": {
            "href": "http://localhost:8080/actuator/threaddump",
            "templated": false
        },
        "metrics-requiredMetricName": {
            "href": "http://localhost:8080/actuator/metrics/{requiredMetricName}",
            "templated": true
        },
        "metrics": {
            "href": "http://localhost:8080/actuator/metrics",
            "templated": false
        },
        "scheduledtasks": {
            "href": "http://localhost:8080/actuator/scheduledtasks",
            "templated": false
        },
        "mappings": {
            "href": "http://localhost:8080/actuator/mappings",
            "templated": false
        }
    }
}
  • /actuator/beans: 애플리케이션에서 생성한 모든 스프링 빈
  • /actuator/conditions: Conditions Evaluation Report와 유사하게 스프링 빈의 생성 조건이 충족됐는지 여부
  • /actuator/configprops: 애플리케이션에서 액세스할 수 있는 모든 Environment 속성
  • /actuator/env: 애플리케이션이 작동하는 환경의 무수한 측면 확인(모든 환경 정보 반환), 개별 configprop값의 출처 확인에 특히 유용
  • /actuator/health: health정보
  • /actuator/heapdump: 트러블 슈팅과 분석을 위해 힙 덤프(heap dump) 시작
  • /actuator/loggers: 모든 컴포넌트의 로깅 수준
  • /actuator/mappings: 모든 엔드포인트 매핑과 세부 지원 정보
  • /actuator/metrics: 애플리케이션에서 현재 캡처 중인 메트릭스
  • /actuator/threaddump: 트러블 슈팅과 분석을 위해 스레드 덤프 시작

  • /actuator/health
    • 세부 속성: Never(기본값), when_authorized, always
    • 프로덕션용 애플리케이션에서는 never 또는 when_authorized ,, 


  • 로깅 수준 선택
    • 개발자가 거의 모든 설정 요소에 "INFO"같은 일반적인 로깅 수준 설정
    • 스프링 부트 애플리케이션에서 실시간으로 로깅 수준을 일시적으로 변경하게 해줌
    • 해당 엔드포인트에 대한 간단한 POST로 로깅 수준을 설정/재설정 하게 해줌

org.springframework.data.web의 기본 로깅 수준

 

post로 configuredLevel 변경 후 확인하면 TRACE로 설정됨

 

'Study > Spring Boot' 카테고리의 다른 글

6. 데이터 파고들기  (2) 2023.12.14
4. 데이터베이스 액세스  (0) 2023.09.10
3. REST API  (0) 2023.09.03