Spring Application 준비 완료 시 작업 수행, Application 실행 후 파일 내용 변경 감지하여 반영

jylee·2023년 12월 18일
0

그냥생각나는거

목록 보기
25/48

application.yaml

resourceFolder: src/main/resources/properties
buildResourceFolder: build/resources/main/properties

yaml 파일

프로젝트폴더/src/main/resources/properties/data1.yaml
프로젝트폴더/src/main/resources/properties/data2.yaml
프로젝트폴더/src/main/resources/properties/data3.yaml

예제 클래스

package com.example.clova_ext.app.util.v3;

import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ScheduledFuture;

@Slf4j
@Data
@Component
@RequiredArgsConstructor
public class YamlLoader implements ApplicationListener<ContextClosedEvent> {

    private ScheduledFuture<?> task;
    private final TaskScheduler taskScheduler;

    private final Environment env;
    // Resource 읽는 객체
    private final PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver;
    // 실제 데이터
    @Getter
    private HashMap<String, LinkedHashMap<String, Object>> properties = new HashMap<>();
    // 파일명
    private ArrayList<String> fileNames = new ArrayList<>();
    // 최근 수정일
    private Map<String, Long> modifiedMap = new HashMap<>();
    private Map<String, Resource> resourceMap = new HashMap<>();
    private Map<String, String> pathMap = new HashMap<>();
    private boolean local;

    public Map<String, Object> getProperties(String key) {
        return properties.get(key + ".yaml");
    }

//
//    @Scheduled(cron = "0/5 * * * * * ")
//    public void loadYaml() {
//        fileNames.forEach(fileName -> {
//            String path = pathMap.get(fileName);
//            File file = new File(path);
//
//            if (modifiedMap.get(fileName) < file.lastModified()) {
//                try {
//                    modifiedMap.put(fileName, file.lastModified());
//                    FileInputStream io = new FileInputStream(file);
//                    properties.put(fileName, new Yaml().load(io));
//                    io.close();
//                    log.info("YamlLoader updated " + fileName);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//        });
//    }


    @EventListener(ApplicationReadyEvent.class)
    private void applicationReadyEvent() throws IOException {
        String tloFile = env.getProperty("tlo.file");
        local = "tlo_local.properties".equals(tloFile);
        log.info("tloFile={}", tloFile);

        Resource[] resources = pathMatchingResourcePatternResolver.getResources("properties/*");
        Arrays.stream(resources).forEach(resource -> {
            try {
                File file = resource.getFile();
                String fileName = resource.getFilename();
                String path = file.getAbsolutePath();
                if (local) {
                    if (path.contains("/")) {
                        path = path.replace("/build/resources/main", "/src/main/resources");
                    } else {
                        path = path.replace("\\build\\resources\\main", "\\src\\main\\resources");
                    }
                    file = new File(path);
                }
                if (!fileNames.contains(fileName)) {
                    fileNames.add(fileName);
                }
                modifiedMap.put(fileName, file.lastModified());
                pathMap.put(fileName, path);
                FileInputStream io = new FileInputStream(file);
                properties.put(fileName, new Yaml().load(io));
                io.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });

        register();
    }

    public void register() {
        Runnable runnable = () -> fileNames.forEach(fileName -> {
            String path = pathMap.get(fileName);
            File file = new File(path);

            if (modifiedMap.get(fileName) < file.lastModified()) {
                try {
                    modifiedMap.put(fileName, file.lastModified());
                    FileInputStream io = new FileInputStream(file);
                    properties.put(fileName, new Yaml().load(io));
                    io.close();
                    log.info("YamlLoader updated " + fileName);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        task = taskScheduler.scheduleAtFixedRate(runnable, 5000);

        log.info("task.isCancelled()={}",task.isCancelled());
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        task.cancel(true);
    }
}
  1. @EventListener(ApplicationReadyEvent.class) 애노테이션이 붙은 메소드가
    Application이 준비가 되면 수행
  2. register() 메소드 수행
  3. TaskScheduler 에 수행할 작업을 등록
  4. 스프링 컨테이너 종료 직전 onApplicationEvent() 메소드 수행 -> task를 해제
profile
ㅎㅇ

0개의 댓글