사용자 도구

사이트 도구


springframework:springboot:properties

SpringBoot Properties

  • SpringBoot 에서 설정 값 외재화
  • jasypt 를 이용해 비밀번호 계통은 암호화 해서 저장해야 한다.
  • 보통 yml을 이용해서 application.yml로 지정한다.
  • YamlPropertiesFactoryBean
  • PropertiesFactoryBean
  • YamlPropertySourceLoader
  • PropertiesPropertySourceLoader

기본값 설정

  • 이미 지정된 property 이면, 해당 값을 사용하고, 그게 아니면 기본값을 사용하는 구조로
  • EXTERNAL_USERNAME/EXTERNAL_PASSWORD 환경 변수 혹은 external.username/external.password 프라퍼티가 존재하면 그 값을 사용하고 그게 아니면 : 뒤에 지정된 값을 사용한다.
testing:
  my:
    username: ${external.username:system}
    password: ${external.password:test}
  • SpEL로 기본값 지정. SpEL은 @Value로 값을 읽는 경우에만 지정 가능하며, @ConfigurationProperties를 사용할 때는 안 된다. 혼란스럽기 때문에 안 사용하는게 나을듯 하다.
testing:
  my:
    username: ${external.username:user}
    password: ${external.password:#{' test'}}
@Value("${testing.my.username}")
private String username;
 
@Value("${testing.my.password}")
private String password;

profile 별 설정

  • 프로필 별로 application-profilename.yml로 파일을 만들 수도 있고,
  • 하나의 파일에서 ---로 구분해서 프로필을 지정할 수도 있다.
  • application.yml에서 profile을 지정하지 않은 프라퍼티는 공통 디폴트 값 역할을 한다. 각 프로필에서 오버라이드하면 변경되고 아니면 디폴트 값이 사용된다.
a:
  b:
    c: default value
---
spring.profiles: local
# 기본값 그대로 사용

---
spring.profiles: develop
a:
  b:
    c: develop-value
---
spring.profiles: production
a:
  b:
    c: production-value

profile include

  • 프로필을 자동 활성화 한다.
  • Spring Boot 2.3 이전에서 사용하는 방식.
  • application.yml
    spring.profiles: production
    spring.profiles.include: a,b
    
    # 혹은
    spring.profiles: production
    spring:
      profiles:
        include:
          - a
          - b
          - c
  • 위 설정은 production profile 에서 자동으로 a, b, c 프로필도 활성화 시키는 역할을 한다.
  • 그러면서 각 프로필의 설정파일을 application-a.yml, application-b.yml 형태로 만들어서 resources 에 두면 이를 읽게 된다.
  • 위 설정을 특정 프로필이 아닌 전역으로 지정하면, 마치 그냥 설정 파일을 include 하는 것 처럼 된다. 하지만 a,b,c라는 프로필이 모르는 사이에 활성화 된다.
  • 각 프로필에서 또 나눠서 spring.profiles: local 이런식으로 특정 프로파일을 지정하고 설정해도 먹지 않고 무시된다. a-develop 이런식으로 별도 프로필을 만들고 active: a-develop 처럼 더 추가해줘야만 한다.
  • 즉, 최초 시작 설정 파일은 application.yml 이어야만 include 된 설정 안에서의 Profile 구분이 올바로 작동한다. 애초에 최초 시작 설정 파일을 application-prod.yml 로 한 상태에서 include는 그 안의 Profile 구분이 무시된다.

별도 Yaml로 PropertySource 적재 방식

// 일반 Bean으로 만들어 주입
@Autowired
private ConfigurableEnvironment env;
 
@Bean
@Order(-1)
PropertySource consumerPropertySource() throws IOException {
    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    PropertySource propertySource =
        loader.load("consumers", new ClassPathResource("consumer.yml"), "develop");
    env.getPropertySources().addLast(propertySource);
    return propertySource;
}
// ApplicationContextInitializerApplicationContextInitializer 구현
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
  try {
    Resource resource = applicationContext.getResource("classpath:application.yml");
    YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
    PropertySource<?> yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null);
    applicationContext.getEnvironment().getPropertySources().addLast(yamlTestProperties);
  } catch (IOException e) {
    throw new RuntimeException(e);
  }
}

YAML을 Property 객체로 변환하기

  • YamlPropertiesFactoryBean 를 사용하여 yaml을 Property 객체로 적재할 수 있다. PropertySource로 등록되는 것은 아니므로 헷갈리면 안된다.
  • 이 경우 @Value(“#propertyObjectName['key']”) 형태로 사용가능해 진다.

YAML을 ''@PropertySource''로 사용하기

@PropertySource(
    value = "classpath:foo.yml", 
    factory = YamlPropertySourceFactory.class
)
public class YamlPropertySourceFactory implements PropertySourceFactory {
 
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) 
      throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(encodedResource.getResource());
 
        Properties properties = factory.getObject();
 
        return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
    }
}

@ConfigurationProperties

PropertySource과 properties 로그로 남기기

@Component
public class LoadedConfigFileListener implements ApplicationListener<ApplicationReadyEvent>, Ordered {
 
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        MutablePropertySources propertySources = event.getApplicationContext().getEnvironment().getPropertySources();
        Iterator<PropertySource<?>> propertySourceIterator = propertySources.iterator();
        propertySourceIterator.forEachRemaining(propertySource -> log.info("Successfully loaded: \"{}\" ({}) into application context", propertySource.getName(), propertySource.getSource()));
    }
 
    @Override
    public int getOrder() {
        return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
    }
}

모든 properties 로그로 남기기

  • 최종적으로 결정된 properties 목록을 확인하고자 할 때, 아래와 같이 ContextRefreshEvent 를 받는 @EventListener Bean을 등록해주고, 거기서 로깅하면 된다.
@Component
public class PropertyLogger  {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyLogger.class);
 
    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) {
        final Environment env = event.getApplicationContext().getEnvironment();
        LOGGER.info("====== Environment and configuration ======");
        LOGGER.info("Active profiles: {}", Arrays.toString(env.getActiveProfiles()));
        final MutablePropertySources sources = ((AbstractEnvironment) env).getPropertySources();
        StreamSupport.stream(sources.spliterator(), false)
                .filter(ps -> ps instanceof EnumerablePropertySource)
                .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames())
                .flatMap(Arrays::stream)
                .distinct()
                .filter(prop -> !(prop.contains("credentials") || prop.contains("password")))
                .forEach(prop -> LOGGER.info("{}: {}", prop, env.getProperty(prop)));
        LOGGER.info("===========================================");
    }
}

addional property 파일지정

  • 기존 프라퍼티 파일들보다 우선순위가 높게 추가 프라퍼티 파일을 지정할 수 있다. 추가되는 것이므로 기존 값도 계속 함께 읽는다.
spring.config.additional-location=classpath:/custom-config,file:./custom-config

JSON을 통한 Override

  • JSON 으로 명령행에서 properties를 override할 수 있다. JSON 으로 여러 프라퍼티를 지정할 수 있다.
  • 시스템 프라퍼티로 : spring.application.json={“keyname”:“value”}
  • 환경 변수로 : SPRING_APPLICATION_JSON={“keyname”:“value”}

EnvironmentPostProcessor 를 통한 프라퍼티 값 후처리

YAML Duration

  • Spring Boot 2.1 부터 Duration 을 지정할 수 있다.
  • 100ms 형태로 시간 단위를 문자로 지정하면 된다.
  • ns for nanoseconds
  • us for microseconds
  • ms for milliseconds
  • s for seconds
  • m for minutes
  • h for hours
  • d for days

참고

springframework/springboot/properties.txt · 마지막으로 수정됨: 2024/06/12 09:00 저자 kwon37xi