[java]springboot에서 manifests에 읽고 쓰기 예제
MANIFEST.MF에 쓰기
- build.gradle 파일에 아래처럼 하면
bootWar { manifest { attributes 'Implementation-Title': project.name attributes 'Implementation-Version': version attributes 'Implementation-Timestamp': new Date() } }
- MANIFEST.MF에 아래 처럼 정보가 추가된다.
MANIFEST.MF에서 읽기
- before
public static void main(String[] args) {
SpringApplication.run(WebuiApplication.class, args);
}
- after
- build.gradle에 아래내용 추가
compile group: 'com.jcabi', name: 'jcabi-manifests', version: '1.1'
- source code고치기
import com.xxx.properties.ApplicationProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import com.jcabi.manifests.Manifests; import java.util.Arrays; import java.util.Date; public static void main(String[] args) { runServer(WebuiApplication.class, args); } protected static ApplicationContext runServer(Class<?> source, String[] args) { // spring-boot 기동 ConfigurableApplicationContext context = null; try { // - 해당 정보는 jar 파일로 실행될 때, manifest.mf 파일을 참고하기 때문에 local 실행시에는 null String applicationVersion = source.getPackage().getImplementationVersion(); // spring boot run SpringApplication springApplication = new SpringApplication(source); context = springApplication.run(args); // applicationProperties 객체 획득 Object object = context.getBean(ApplicationProperties.class); ApplicationProperties applicationProperties = (ApplicationProperties) object; // 서버 버전 정보 설정 applicationProperties.setVersion(applicationVersion); // Manifests 파일에서 timestamp 정보를 획득 // - 해당 정보는 jar 파일로 실행될 때, manifest.mf 파일을 참고하기 때문에 local 실행시에는 null if (Manifests.exists("Implementation-Timestamp")) applicationProperties.setPackageCreatedTime(Manifests.read("Implementation-Timestamp")); // 서버 기동시 설정한 Active Profile String[] activeProfiles = context.getEnvironment().getActiveProfiles(); if (activeProfiles != null) applicationProperties.setActiveProfiles( Arrays.asList(activeProfiles) ); // 서버 기동 시간 저장 applicationProperties.setBootTime(new Date(context.getStartupDate())); // 서버 기동 완료 설정 // applicationProperties.setStartup(true); // 출력해보자. log.info("{}", applicationProperties.toString()); } finally { if (context == null) log.error("start fail!"); } return context; }
package com.xxx.webui.properties; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.*; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @Slf4j @Getter @Setter @ConfigurationProperties(value = "app") @Component public class ApplicationProperties { @JsonIgnore @Setter(AccessLevel.NONE) @Getter(AccessLevel.NONE) public final Object shutdownMonitor = new Object(); // set from application.yaml private String name; private String description; // set from main class private String version; @Getter(AccessLevel.NONE) private List<String> activeProfiles; private String packageCreatedTime; @Setter(AccessLevel.NONE) private final AtomicBoolean startup = new AtomicBoolean(false); @JsonIgnore @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private AtomicBoolean shutdown; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul") private Date bootTime; public List<String> getActiveProfiles() { if (activeProfiles != null) return activeProfiles; String value = System.getProperty("spring.profiles.active"); log.info("getActiveProfiles : {}" , value); return value != null ? Arrays.asList(value.split(",")) : Collections.emptyList(); } public void setStartup(boolean status) { this.startup.set(status); } // 종료 시점에서만 호출 하자. public void setShutdown() { if (shutdown == null) { synchronized (this.shutdownMonitor) { log.info("Setting shutdown variable to true"); shutdown = new AtomicBoolean(true); shutdownMonitor.notifyAll(); } } } @JsonIgnore public boolean hasRealProfile() { return getActiveProfiles().stream().anyMatch(v -> v.contains("real")); } ... }
actuate를 통해 rest api 로 정보 확인하기
package com.xxx.actutaor;
import com.xxx.properties.ApplicationProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.boot.actuate.info.MapInfoContributor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
//SpringBoot 에서 자동으로 생성되던, infoEndpoint 객체를 직접 생성하기
@Slf4j
@Configuration
public class InfoConfiguration {
private final Map<String, Object> infoMap = new LinkedHashMap<String, Object>();
@Autowired
private ApplicationProperties applicationProperties;
@Bean
public InfoEndpoint infoEndpoint() {
addInfo("app", applicationProperties);
//addInfo 를 통해 더 필요한 정보 넣자.
List<InfoContributor> result = new ArrayList<>();
result.add(new MapInfoContributor(infoMap));
return new InfoEndpoint(result);
}
public void addInfo(String key, Object value) {
infoMap.put(key, value);
}
}