프레임워크 · Spring · 설정 · 자동구성 · 프로파일

Spring · 설정, 자동 구성, 프로파일

Spring Boot? 의 가장 큰 매력은 "설정을 거의 안 해도 알아서 돌아간다" 입니다. 라이브러리를 하나 추가하기만 하면, Spring이 "아, 이걸 쓰려는구나" 하고 필요한 부품을 스스로 조립해 줍니다(자동 구성). 그리고 바꾸고 싶은 값만 설정 파일 에 적으면 그 부분만 덮어쓰입니다. 이 페이지에서는 스타터로 기능을 들여오는 법, 자동 구성의 원리, 설정값을 외부에서 주입하는 법, 환경별로 다르게 동작시키는 프로파일 까지 차근차근 풀어봅니다.

1. 스타터 — 기능을 묶음으로 들여오기

어떤 기능을 쓰려면 보통 라이브러리 여러 개를 일일이 골라 버전까지 맞춰 넣어야 합니다. 스타터(starter) 는 이 번거로움을 없애 줍니다. "웹을 만들고 싶다"면 spring-boot-starter-web 하나만 넣으면, 그 안에 필요한 라이브러리(웹 서버 톰캣, JSON 변환기 잭슨, MVC 등)가 검증된 버전 조합으로 한 묶음 으로 딸려 옵니다. 마치 라면을 끓일 때 면·스프·건더기가 한 봉지에 들어 있는 것과 같습니다.

이사할 때 "주방 세트", "침실 세트"처럼 묶음으로 주문하는 것을 떠올려 보세요. 컵·접시·냄비를 하나씩 고르는 대신 "주방 세트 하나요" 하면 서로 어울리는 물건이 한 번에 옵니다. 스타터가 바로 그 "세트 주문"입니다.

아래는 이 프로젝트의 build.gradle 에 실제로 들어 있는 주요 스타터입니다.

스타터들여오는 기능
spring-boot-starter-web웹·REST API? 서버. 내장 톰캣 + Spring MVC + 잭슨(JSON) 포함.
spring-boot-starter-data-jpaJPA?/Hibernate로 DB를 객체처럼 다루는 ORM? 기능.
spring-boot-starter-data-jdbcJPA보다 가벼운, JDBC 기반 데이터 접근.
spring-boot-starter-securitySpring Security? — 인증·인가(로그인·권한) 기능.
spring-boot-starter-validationBean Validation? — 입력값 검증(@NotNull 등).
spring-boot-starter-actuator운영용 모니터링 엔드포인트(상태 점검 등). 아래 7번에서 다룸.
spring-boot-starter-jooqjOOQ로 타입 안전한 SQL을 작성하는 기능(DSLContext 자동 구성).
spring-boot-starter-test테스트 도구 묶음(JUnit, Mockito, AssertJ 등). 테스트에서만 사용.
스타터가 아닌 라이브러리도 함께

이 프로젝트는 스타터 외에도 PostgreSQL 드라이버, Liquibase, JWT(jjwt), QueryDSL, MyBatis, Lombok 등을 직접 의존성으로 넣어 씁니다. 스타터는 "묶음 주문"일 뿐, 개별 라이브러리를 따로 추가하는 것도 얼마든지 가능합니다.

2. 자동 구성 — 클래스패스를 보고 알아서 조립

스타터로 라이브러리를 들여오면, Spring Boot가 자동 구성(auto-configuration) 으로 필요한 빈(객체)을 스스로 만들어 등록합니다. 핵심 아이디어는 단순합니다 — "있는 부품을 보고 판단한다." 예를 들어 클래스패스(앱이 실행될 때 들고 있는 라이브러리 목록)에 PostgreSQL 드라이버가 보이면 "DB를 쓰려는구나" 하고 데이터소스 빈을 자동으로 준비합니다.

@SpringBootApplication 한 줄에 들어있는 것

@SpringBootApplication 은 세 가지를 묶은 애너테이션입니다.

  • @SpringBootConfiguration — 사실상 @Configuration. 이 클래스가 설정의 출발점임을 표시.
  • @EnableAutoConfiguration — 자동 구성 기능을 켠다. 이게 핵심 스위치.
  • @ComponentScan — 이 클래스가 있는 패키지(여기선 com.example.study)와 그 하위를 빈으로 스캔.

자동 구성이 "있는 부품을 보고 판단한다"는 것은, 내부적으로 조건부 구성 애너테이션으로 이루어집니다. 빈을 등록하기 전에 "이 조건이 맞을 때만 등록해"라고 단서를 다는 것이죠.

조건 애너테이션의미 — "이럴 때만 빈을 등록"
@ConditionalOnClass특정 클래스가 클래스패스에 있을 때만. (예: JPA 라이브러리가 있으면 JPA 설정을 켠다)
@ConditionalOnMissingBean같은 타입 빈이 아직 없을 때만. 즉 내가 직접 만든 빈이 있으면 자동 구성은 비켜선다.
@ConditionalOnProperty특정 설정값이 있을 때만. (예: 어떤 기능을 true로 켰을 때만)
@ConditionalOnMissingClass특정 클래스가 없을 때만.
자동 구성은 눈치 빠른 비서와 같습니다. 책상에 커피잔이 보이면(클래스 존재) 받침을 가져다 두고, 이미 받침을 내가 깔아 뒀다면(빈 존재) 손대지 않습니다. @ConditionalOnMissingBean 이 바로 이 "주인이 이미 해 놨으면 건드리지 않는다"는 매너입니다.

이 "주인이 해 놓은 게 우선"이라는 성질 덕분에 자동 구성은 비침습적(non-invasive) 입니다. 내가 @Bean 으로 직접 만든 객체가 있으면 자동 구성은 양보하고 물러납니다. 그래서 기본은 알아서 돌아가되, 원하는 부분만 직접 손볼 수 있습니다. 어떤 자동 구성이 적용됐는지 궁금하면 실행 시 --debug 옵션을 주면 적용/미적용 내역이 로그로 나옵니다.

3. 외부 설정 — properties와 yml

코드 안에 값을 박아두면 바꿀 때마다 다시 빌드해야 합니다. Spring Boot는 값을 코드 바깥(외부) 에 두도록 권합니다. 가장 흔한 곳이 src/main/resourcesapplication.properties 또는 application.yml 입니다. 둘은 적는 문법만 다르고 역할은 같습니다.

// application.properties — 키=값, 평면적
server.port=8084
spring.datasource.url=jdbc:postgresql://localhost:5432/studydb
spring.jpa.show-sql=true
# application.yml — 계층(들여쓰기) 구조, 중복 접두사를 줄임
server:
  port: 8084
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/studydb
  jpa:
    show-sql: true

이 프로젝트는 application.properties 를 사용합니다. 같은 설정을 두 형식으로 적은 것뿐, 내용은 동일합니다.

3-1. 설정 우선순위 — 누가 누구를 덮어쓰나

설정값은 한 곳에만 있는 게 아닙니다. 파일·환경변수·실행 옵션 등 여러 곳에서 올 수 있고, 같은 키가 겹치면 우선순위가 높은 쪽이 이깁니다. 아래는 위로 갈수록(아래를 덮어씀) 강한 순서입니다.

설정 출처우선순위
커맨드라인 인자 --server.port=9000가장 강함 (다른 모든 것을 덮어씀)
OS 환경변수 SPRING_DATASOURCE_URL=...강함
application-{프로파일}.properties중간 (기본 파일을 덮어씀)
application.properties / .yml (기본)약함
코드에 박힌 기본값가장 약함
운영에서 비밀값을 안전하게 — 환경변수 오버라이드

비밀번호 같은 값을 파일에 적기 꺼려진다면, 파일엔 개발용 기본값만 두고 운영 서버에서는 환경변수로 덮어쓰면 됩니다. 환경변수는 점(.)을 못 쓰므로 대문자+밑줄로 적습니다. 이것을 느슨한 바인딩(relaxed binding) 이라 합니다. 예를 들어 spring.datasource.url 은 환경변수 SPRING_DATASOURCE_URL 로, spring.jpa.hibernate.ddl-autoSPRING_JPA_HIBERNATE_DDL_AUTO 로 적으면 같은 키에 연결됩니다. 재빌드 없이 실행 시점에 --server.port=9000 같은 커맨드라인 인자로도 바꿀 수 있습니다.

4. 설정값을 코드로 주입받기

파일에 적은 값을 코드에서 꺼내 쓰는 방법은 두 가지입니다. 값 하나를 콕 집어 넣는 @Value 와, 관련 값을 묶어 객체로 받는 @ConfigurationProperties 입니다.

4-1. @Value — 값 하나씩 주입

@Value("${키}") 로 설정값 하나를 필드에 바로 꽂습니다. : 뒤에 기본값도 줄 수 있어, 그 키가 없으면 기본값이 쓰입니다. 간단하지만 값이 많아지면 흩어져서 관리가 번거롭습니다.

@Service
public class JwtService {

  @Value("${app.jwt.secret}")            // 설정에서 비밀키 주입
  private String secret;

  @Value("${app.jwt.expirationMs}")      // 토큰 만료 시간(ms)
  private long expirationMs;

  @Value("${app.stage:dev}")             // 없으면 기본값 "dev"
  private String stage;
}

4-2. @ConfigurationProperties — 묶음으로 타입 안전하게

같은 접두사(prefix)로 시작하는 값들을 한 객체에 통째로 받습니다. 키 이름이 필드 이름과 자동으로 연결(바인딩)되고, 타입(숫자·불리언 등)도 알아서 변환됩니다. 관련 설정이 한 곳에 모여 읽기 좋고, 오타가 줄어듭니다.

@ConfigurationProperties(prefix = "app.jwt")   // app.jwt.* 를 묶어서 바인딩
public class JwtProperties {
  private String secret;             // app.jwt.secret
  private long expirationMs;         // app.jwt.expirationMs
  private long refreshExpirationMs;  // app.jwt.refreshExpirationMs
  // getter / setter
}

이렇게 만든 설정 객체를 빈으로 등록하는 방법은 두 가지입니다.

방법설명
@EnableConfigurationProperties(JwtProperties.class)설정 클래스 위에 붙여 특정 프로퍼티 클래스만 빈으로 등록.
@ConfigurationPropertiesScan지정 패키지를 훑어 @ConfigurationProperties 클래스를 모아서 등록.
검증을 결합 — @Validated

@ConfigurationProperties 클래스에 @Validated 를 붙이고 필드에 검증? 애너테이션(@NotBlank 등)을 달면, 잘못된 설정값으로 앱이 시작될 때 바로 실패 시켜 알려줍니다. 운영 중 엉뚱한 값으로 도는 사고를 막는 안전장치입니다. @Value 에는 이런 검증 기능이 없습니다.

5. 프로파일 — 환경별로 다르게

개발 PC, 테스트 서버, 운영 서버는 DB 주소나 로그 수준이 서로 다릅니다. 프로파일(profile) 은 이런 "환경 꼬리표"입니다. 환경마다 다른 설정 파일과 빈을 준비해 두고, "지금은 어느 환경"인지만 골라 켜면 그에 맞는 것이 적용됩니다.

요소설명
application-{프로파일}.properties프로파일별 설정 파일. 예: application-dev.properties, application-prod.properties.
spring.profiles.active=prod지금 켤 프로파일을 지정. 켜진 프로파일 파일이 기본 파일을 덮어씀.
@Profile("prod")그 프로파일일 때만 등록되는 빈/설정 클래스를 표시.
# application-dev.properties — 개발 환경
spring.datasource.url=jdbc:postgresql://localhost:5432/studydb
spring.jpa.show-sql=true        # 개발 땐 SQL을 콘솔에 보기
# application-prod.properties — 운영 환경
spring.datasource.url=jdbc:postgresql://db.prod:5432/studydb
spring.jpa.show-sql=false       # 운영 땐 SQL 로그를 끔
// 운영에서만 동작하는 빈
@Configuration
@Profile("prod")
public class ProdMailConfig {
  @Bean
  public MailSender realMailSender() { /* 실제 메일 발송 */ return null; }
}
프로파일 켜는 법

실행할 때 --spring.profiles.active=prod 커맨드라인 인자나 SPRING_PROFILES_ACTIVE=prod 환경변수로 켤 수 있습니다. 아무것도 안 켜면 application.properties 의 기본값만 적용됩니다. 이 프로젝트는 프로파일별 파일을 따로 두는 대신, app.stage 라는 자체 설정값(dev | test | prod)으로 단계를 구분합니다.

6. 직접 구성 — 내가 손으로 빈을 정의

자동 구성으로 부족하거나, 외부 라이브러리 객체를 내 방식대로 만들어야 할 때는 직접 빈을 정의합니다. (이 주제는 IoC · DI · 빈 페이지에서 더 깊이 다룹니다.)

애너테이션역할
@Configuration + @Bean설정 클래스 안의 메서드가 반환하는 객체를 빈으로 등록.
@Import다른 설정 클래스를 끌어와 합친다.
@Conditional(...)특정 조건이 맞을 때만 빈을 등록(조건은 코드로 정의).
@Configuration
public class AppConfig {

  @Bean                                  // 외부 라이브러리 객체를 직접 조립
  public ObjectMapper objectMapper() {
    ObjectMapper m = new ObjectMapper();
    m.registerModule(new JavaTimeModule());
    return m;
  }
}

7. Actuator — 앱의 건강검진 창구

spring-boot-starter-actuator 는 운영 중인 앱의 상태를 들여다보는 엔드포인트(점검 창구) 들을 열어 줍니다. 가장 많이 쓰는 것이 /actuator/health 로, "앱과 DB가 정상인가?"를 알려줍니다. 로드밸런서나 쿠버네티스가 이 창구를 주기적으로 두드려 살아 있는지 확인합니다.

엔드포인트알려주는 것
/actuator/health앱·DB 등 구성요소의 정상 여부(UP/DOWN).
/actuator/info앱 정보(버전 등, 직접 채워 넣음).
/actuator/metrics메모리·요청 수 같은 지표.

보안상 기본으로는 일부 창구만 열려 있습니다. 어떤 창구를 웹으로 공개할지는 설정으로 고릅니다.

# health, info 창구만 웹으로 공개
management.endpoints.web.exposure.include=health,info

8. 실제 프로젝트 application.properties

아래는 이 프로젝트의 src/main/resources/application.properties 에 실제로 들어 있는 주요 설정값입니다. (비밀키 값 자체는 보안을 위해 생략)

값 / 의미
spring.application.name이 프로젝트 — 앱 이름.
server.port8084 — 서버가 뜨는 포트.
spring.datasource.urljdbc:postgresql://localhost:5432/studydb?currentSchema=lds — DB 주소(스키마 lds).
spring.datasource.driverClassNameorg.postgresql.Driver — PostgreSQL 드라이버.
spring.datasource.usernamepostgres — DB 접속 계정.
spring.jpa.open-in-viewtrue — 요청이 끝날 때까지 영속성 컨텍스트 유지.
spring.jpa.show-sqltrue — 실행되는 SQL을 콘솔에 출력.
spring.jpa.properties.hibernate.format_sqltrue — SQL 로그를 보기 좋게 줄바꿈.
spring.liquibase.change-logclasspath:/db/changelog/changelog-index.yaml — Liquibase 변경 이력 파일.
spring.jooq.sql-dialectPOSTGRES — jOOQ가 쓸 SQL 방언.
spring.servlet.multipart.max-file-size100MB — 단일 업로드 파일 최대 크기.
spring.servlet.multipart.max-request-size100MB — 요청 전체 최대 크기.
logging.level.com.example.studyDEBUG — 앱 패키지 로그 수준.
app.jwt.secretJWT? 서명용 비밀키(값은 생략).
app.jwt.expirationMs43200000 — Access 토큰 만료(12시간).
app.jwt.refreshExpirationMs604800000 — Refresh 토큰 만료(7일).
app.upload.path${user.home}/temp — 업로드 저장 경로(다른 값을 끌어 씀).
app.stagedev — 단계 구분(prod | test | dev).
app.* 는 우리가 만든 키

spring.* 으로 시작하는 키는 Spring이 정해둔 표준 키지만, app.jwt.*, app.upload.*, app.stage 처럼 app.* 으로 시작하는 키는 이 프로젝트가 직접 만든 사용자 정의 설정 입니다. 이런 값은 @Value@ConfigurationProperties(prefix = "app.jwt") 로 코드에서 꺼내 씁니다.

한눈에 — 핵심 정리

개념핵심
스타터관련 라이브러리를 검증된 버전 묶음으로 한 번에 들여옴.
자동 구성클래스패스를 보고 필요한 빈을 알아서 등록. @EnableAutoConfiguration 으로 켜짐.
@SpringBootApplication@SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan 묶음.
조건부 구성@ConditionalOnClass / @ConditionalOnMissingBean 등으로 "있을 때만/없을 때만" 등록.
외부 설정application.properties/.yml. 커맨드라인 > 환경변수 > 프로파일 파일 > 기본 파일 순으로 덮어씀.
@Value값 하나를 콕 집어 주입. 기본값 ${키:기본} 가능.
@ConfigurationProperties같은 접두사 값들을 객체로 묶어 타입 안전하게 바인딩. @Validated 결합 가능.
프로파일환경 꼬리표. application-{프로파일}.properties + spring.profiles.active + @Profile.
직접 구성@Configuration + @Bean 으로 손수 정의. 자동 구성보다 우선.
Actuator운영 점검 창구. /actuator/health + management.endpoints.web.exposure.
이 프로젝트와의 관계

이 프로젝트의 백엔드(com.example.study 패키지)는 application.properties 로 설정하며, 포트는 8084, DB는 studydb(스키마 lds)에 연결하고 Liquibase 로 테이블을 관리합니다. 버전은 Spring Boot 3.3.1 / Spring Framework 6.x / Java 17 / Jakarta EE 10 입니다. 웹·data-jpa·security·validation·actuator·data-jdbc·jooq 스타터를 사용합니다. 설정과 실행 환경을 더 보려면 → 백엔드 환경, 실행 방법.

다음 단계