스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초

스프링부트 핵심 가이드(장정우 지음) - 액추에이터 주요 기능 살펴보기, 액추에이터 커스텀 기능 만들기

개발학생 2026. 2. 19. 19:36
반응형

*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성  

 

[Java] 차근차근 Java 설치하기 (JDK17, Window 11)

자바 개발 도구 설치 방법에 대해서 알아보겠습니다. Java17은 LTS(Long Term Support : 장기 지원) 릴리즈로 1년 후까지 기술 지원 및 버그를 개선한 서비스를 제공받을 수 있습니다. 업데이트 버전을 꾸

yungenie.tistory.com

 

[Windows] Spring Tool Suite 4(STS 4) 다운로드 및 설치

STS란?Spring Tool Suite(STS)는 스프링 프로젝트를 생성하고, 개발할 수 있게 해주는 도구입니다. STS 설치 과정에 대해 설명드리겠습니다. 설치 파일 다운로드STS 공식 사이트에서 설치 파일을 다운로

priming.tistory.com

 

MySQL :: Download MySQL Community Server

Select Version: 9.3.0 Innovation 8.4.5 LTS 8.0.42 Select Operating System: Select Operating System… Microsoft Windows Ubuntu Linux Debian Linux SUSE Linux Enterprise Server Red Hat Enterprise Linux / Oracle Linux Fedora Linux - Generic Oracle Solaris mac

dev.mysql.com

  • Gradle

**STS에서 Gradle 프로젝트 생성한 과정 

 

*** 함께 보면 좋은 글

2026.02.04 - [스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초] - 스프링부트 핵심 가이드(장정우 지음) - 예외 처리 에러 해결, 액추에이터 활용하기

 

스프링부트 핵심 가이드(장정우 지음) - 예외 처리 에러 해결, 액추에이터 활용하기

*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성 Windows11(윈도우 11) 환경자바 JDK 17 버전 설치 https://yungenie.tistory.com/11 [Java] 차근차근 Java 설치하기 (JDK17, Window 11)자바 개발 도구 설치 방법

keep-programming-study.tistory.com

 

 

1. 액추에이터 주요 기능 살펴보기 

1) 애플리케이션 기본 정보(/info)

  • 액추에이터의 /info 엔드포인트를 활용하면 가동 중인 애플리케이션의 정보를 볼 수 있음
  • application.properties 파일 내에 다음과 같이 애플리케이션 정보 속성을 작성한 후 서버 실행
# 액추에이터 info 정보 설정
info.organization.name=programming
info.contact.email=abc@defg.co.kr
info.contact.phoneNumber=010-1234-5678

에러 발생!

2026-02-05 19:00:42.291 [main] WARN o.h.e.j.e.i.JdbcEnvironmentInitiator - HHH000342: Could not obtain connection to query metadata

org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Public Key Retrieval is not allowed] [n/a]

at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:100)

at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:58)

at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)

at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94)

  • 액추에이터를 추가하면, Spring Boot가 자동으로 DataSource HealthIndicator를 등록:
    이때 spring-boot-starter-actuator가 들어오면서, DataSource 관련 빈을 확인하다가 Hibernate/JPA가 MySQL 드라이버 설정을 기본값으로 잡음 
    -> application.properties 다음과 같이 수정하여 해결 
spring.application.name=study

# 테스트용 인메모리 H2 DB 설정
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# JPA 설정
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

# H2 콘솔 (선택)
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console


# Spring Boot 3.x 계열이면 아래 두 줄 반드시 붙임
management.info.env.enabled=true 
management.info.defaults.enabled=true

# 액추에이터 info 정보 설정
info.organization.name=programming
info.contact.email=abc@defg.co.kr
info.contact.phoneNumber=010-1234-5678


# 액추에이터 엔드포인트 노출 설정(모든 엔드포인트 열기)
management.endpoints.web.exposure.include=*
# 액추에이터 health 상세 내역 활성화
management.endpoint.health.show-details=always
  • http://localhost:8080/actuator/info에 접속 시 다음과 같이 뜸 
 

http://localhost:8080/actuator/info에 접속 결과

2) 애플리케이션 상태(/health)

  • 주로 네트워크 계층 중 L4(Loadbalancing) 레벨에서 애플리케이션의 상태를 확인하기 위해 사용 
  • http://localhost:8080/actuator/health에 접속 시 다음과 같이 뜸 
    -> management.endpoint.health.show-details=always가 있으므로, health 상세 내역이 보이는 것 

http://localhost:8080/actuator/health에 접속 결과(pretty print 적용, health 상세 내역 보임)

3) 빈 정보 확인(/beans)

  • 스프링 컨테이너에 등록된 빈의 전체 목록을 표시(JSON 형식으로 빈 정보를 반환)
  • http://localhost:8080/actuator/beans에 접속 시 다음과 같이 뜸 

http://localhost:8080/actuator/beans에 접속 결과(pretty print 적용, 기존 프로젝트에 연결하여 엄청난 bean들이 보임)

 

4) 스프링 부트의 자동설정 내역 확인(/conditions)

  • 스프링부트의 자동설정(AutoConfiguration) 조건 내역 확인
  • http://localhost:8080/actuator/conditions에 접속 시 다음과 같이 뜸

http://localhost:8080/actuator/conditions에 접속 결과(pretty print 적용, 기존 프로젝트에 연결하여 엄청난 conditions들이 보임)

5) 스프링 환경변수 정보(/env)

  • 스프링의 환경변수 정보 확인(application.properties 파일의 변수들, OS/JVM의 환경변수들이 표시됨)
  • http://localhost:8080/actuator/env에 접속 시 다음과 같이 뜸

http://localhost:8080/actuator/env에 접속 결과(pretty print 적용, 기존 프로젝트에 연결하여 엄청난 env들이 보임)

6) 로깅 레벨 확인(/loggers)

  • 애플리케이션의 로깅 레벨 수준 확인
  • http://localhost:8080/actuator/loggers에 접속 시 다음과 같이 뜸

http://localhost:8080/actuator/loggers에 접속 결과(pretty print 적용, 기존 프로젝트에 연결하여 엄청난 loggers들이 보임

2. 액추에이터 커스텀 기능 만들기

  • 개발자의 요구사항에 맞춰, 커스텀 기능 설정 및 개발이 가능
  • 커스텀 기능 개발 방식: 기존 기능에 내용을 추가 or 새로운 엔드포인트를 개발

1) 기존 기능에 내용 추가: InfoContributer 인터페이스를 구현하는 클래스 생성

package com.example.demo.config.actuator;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.actuate.info.Info.Builder;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;

/**
 * Spring Boot Actuator의 Info 엔드포인트에
 * 커스텀 정보를 추가하기 위한 클래스
 */
@Component // 스프링 빈으로 등록되어 자동으로 Actuator에 연결
public class CustomInfoContributor implements InfoContributor {

    /**
     * InfoContributor 인터페이스의 구현 메서드
     * : 애플리케이션의 /actuator/info 엔드포인트에 원하는 정보를 추가
     */
    @Override
    public void contribute(Builder builder) {
        // Info에 담을 커스텀 데이터를 저장할 Map 생성
        Map<String, Object> content = new HashMap<>();
        
        // key-value 형태로 원하는 정보 추가
        content.put("code-info", "InfoContributor 구현체에서 정의한 정보");
        
        // builder에 "custom-info-contributor"라는 이름으로 Map을 등록
        builder.withDetail("custom-info-contributor", content);
    }
}

*서버 재실행 후 http://localhost:8080/actuator/info에 접속

http://localhost:8080/actuator/info에 접속 한 결과(pretty print 적용)

2) 새로운 엔드포인트 개발: 커스텀 엔드포인트 클래스 생성

  • @Endpoint 어노테이션으로 빈에 추가된 객체들은, @ReadOperation @WriteOperation @DeleteOperation 어노테이션으로 JMX나 HTTP를 통해 커스텀 엔드포인트를 노출시킬 수 있음 
    -> JMX에서만 사용하거나 HTTP에서만 사용하고 싶을 경우, @JmxEndpoint @WebEndpoint를 사용하면 됨
package com.example.demo.config.actuator;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;

/**
 * Spring Boot Actuator에 커스텀 엔드포인트를 추가하는 클래스
 * : "/actuator/note" 경로로 접근할 수 있으며, Read, Write, Delete 기능을 제공
 */
@Component // 스프링 빈으로 등록되어 Actuator에 자동 연결
@Endpoint(id="note") // 엔드포인트 ID를 "note"로 지정하여, /actuator/note 로 접근 가능
public class NoteEndpoint {
    
    // 엔드포인트에서 관리할 데이터를 저장하는 Map
    private Map<String, Object> noteContent = new HashMap<>();
    
    /**
     * ReadOperation: GET 요청 시 호출
     * : 현재 저장된 noteContent 전체를 반환
     */
    @ReadOperation
    public Map<String, Object> getNote() {
        return noteContent;
    }
    
    /**
     * WriteOperation: POST 요청 시 호출
     * : key-value 형태로 데이터를 저장하고 전체 Map을 반환
     */
    @WriteOperation
    public Map<String, Object> writeNote(String key, Object value) {
        noteContent.put(key, value);
        return noteContent;
    }
    
    /**
     * DeleteOperation: DELETE 요청 시 호출
     * : 전달받은 key에 해당하는 데이터를 삭제하고 전체 Map을 반환
     */
    @DeleteOperation
    public Map<String, Object> deleteNote(String key) {
        noteContent.remove(key);
        return noteContent;
    }
}

(1) 서버 실행 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.

2026-02-19 19:01:45.279 [main] ERROR o.s.boot.SpringApplication - Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'healthEndpointWebMvcHandlerMapping' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.class]: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping]: Factory method 'healthEndpointWebMvcHandlerMapping' threw exception with message: Failed to extract parameter names for public java.util.Map com.example.demo.config.actuator.NoteEndpoint.deleteNote(java.lang.String)

at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657)

at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1375)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1205)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529)

at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1222)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1188)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1123)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627)

at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)

at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)

at com.example.demo.StudyApplication.main(StudyApplication.java:11)

  • 서버실행에 에러발생!! 역시 IntelliJ 환경이었다면 발생하지 않았을 에러...
    -> 파라미터 이름을 명시적으로 지정할 수 있는 액추에이터의 @Selector 어노테이션을 사용하도록 수정하면 해결 (요청에서 key값 추출 가능) + Spring Boot 3.5.3 환경에서는 메서드 시그니처를 Actuator가 이해할 수 있는 형태로 맞춰야 함
package com.example.demo.config.actuator;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;

/**
 * Spring Boot Actuator에 커스텀 엔드포인트를 추가하는 클래스
 * : "/actuator/note" 경로로 접근할 수 있으며, Read, Write, Delete 기능을 제공
 */
@Component // 스프링 빈으로 등록되어 Actuator에 자동 연결
@Endpoint(id="note") // 엔드포인트 ID를 "note"로 지정하여, /actuator/note 로 접근 가능
public class NoteEndpoint {
    
    // 엔드포인트에서 관리할 데이터를 저장하는 Map
    private Map<String, String> noteContent = new HashMap<>();
    
    /**
     * ReadOperation: GET 요청 시 호출
     * : 현재 저장된 noteContent 전체를 반환
     */
    @ReadOperation
    public Map<String, String> getNote() {
        return noteContent;
    }
    
    /**
     * WriteOperation: POST 요청 시 호출
     * : key-value 형태로 데이터를 저장하고 전체 Map을 반환
     */
    @WriteOperation
    public Map<String, String> writeNote(@Selector String key, String value) {
        noteContent.put(key, value);
        return noteContent;
    }
    
    /**
     * DeleteOperation: DELETE 요청 시 호출
     * : 전달받은 key에 해당하는 데이터를 삭제하고 전체 Map을 반환
     */
    @DeleteOperation
    public Map<String, String> deleteNote(@Selector String key) {
        noteContent.remove(key);
        return noteContent;
    }
}
  • 추가로, 프로젝트 우클릭 -> Properties -> Java Compiler -> Store information about method parameters (-parameters) 체크하니까 서버실행 됨!! 
    -> 이걸하면... 그동안 @RequestBody가 안되서 @RequestParameter를 썼던 문제도 해결가능할지도??

(2) 서버 실행 후, Talend API Tester(크롬 확장 프로그램)에서 커스텀 엔드포인트 호출 [Send를 클릭하면 됨]

  • GET 요청: 값을 넣지 않은 상태이기에 JSON 형태의 빈 값이 보임 

  • POST 호출 후 다시 GET 호출: 값을 추가하여 /note에서 확인이 가능한 상태  

  • DELETE 호출 후 다시 GET 호출: 값을 삭제하여 /note가 다시 빈 값이 된 상태  

반응형