Java配置备份案例如何实操

wen java案例 28

本文目录导读:

Java配置备份案例如何实操

  1. 基础配置文件备份方案
  2. 实战:Spring Boot配置备份工具
  3. 配置文件:application.yml
  4. 使用示例
  5. 最佳实践建议

我来为您提供一个完整的Java配置备份实操案例,从基础到高级逐步演示。

基础配置文件备份方案

简单文件复制备份

import java.io.*;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ConfigBackupBasic {
    public static void main(String[] args) {
        String configPath = "application.properties";
        String backupDir = "backup/";
        try {
            // 创建备份
            File backup = backupConfig(configPath, backupDir);
            System.out.println("备份成功: " + backup.getAbsolutePath());
            // 验证备份
            boolean valid = verifyBackup(new File(configPath), backup);
            System.out.println("备份验证: " + (valid ? "通过" : "失败"));
        } catch (IOException e) {
            System.err.println("备份失败: " + e.getMessage());
        }
    }
    public static File backupConfig(String sourcePath, String backupDir) 
            throws IOException {
        // 创建备份目录
        Path dirPath = Paths.get(backupDir);
        if (!Files.exists(dirPath)) {
            Files.createDirectories(dirPath);
        }
        // 生成备份文件名(添加时间戳)
        String timestamp = LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        String backupName = "config_backup_" + timestamp + ".properties";
        // 执行复制
        Path source = Paths.get(sourcePath);
        Path backup = dirPath.resolve(backupName);
        Files.copy(source, backup, StandardCopyOption.REPLACE_EXISTING);
        return backup.toFile();
    }
    public static boolean verifyBackup(File original, File backup) {
        return original.length() == backup.length() && 
               original.lastModified() <= backup.lastModified();
    }
}

带校验的文件备份

import java.io.*;
import java.security.*;
import java.util.zip.*;
public class ConfigBackupWithCheck {
    public static void main(String[] args) {
        String configFile = "application.yml";
        String backupFile = "backup/application_backup.yml";
        try {
            // 1. 计算原始文件MD5
            String originalMd5 = calculateMD5(configFile);
            System.out.println("原始MD5: " + originalMd5);
            // 2. 创建压缩备份
            createCompressedBackup(configFile, backupFile + ".gz");
            // 3. 验证备份完整性
            String backupMd5 = calculateMD5(backupFile + ".gz");
            verifyBackupIntegrity(originalMd5, backupMd5);
        } catch (Exception e) {
            System.err.println("备份过程出错: " + e.getMessage());
        }
    }
    private static String calculateMD5(String filePath) {
        try (InputStream is = Files.newInputStream(Paths.get(filePath))) {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
            StringBuilder hexString = new StringBuilder();
            for (byte b : md.digest()) {
                hexString.append(String.format("%02x", b));
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException("计算MD5失败", e);
        }
    }
    private static void createCompressedBackup(String source, String backup) 
            throws IOException {
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(backup);
             GZIPOutputStream gzip = new GZIPOutputStream(fos)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                gzip.write(buffer, 0, len);
            }
            gzip.finish();
        }
    }
    private static void verifyBackupIntegrity(String original, String backup) 
            throws SecurityException {
        if (!original.equals(backup)) {
            throw new SecurityException("备份文件完整性校验失败!");
        }
        System.out.println("备份完整性校验通过");
    }
}

实战:Spring Boot配置备份工具

Spring Boot配置备份服务

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class ConfigBackupService {
    @Value("${app.config.backup.dir:./backup}")
    private String backupDir;
    @Value("${app.config.backup.max-versions:10}")
    private int maxVersions;
    @Value("${app.config.files:application.properties,application.yml}")
    private String[] configFiles;
    private Map<String, ConfigBackupHistory> backupHistories = new ConcurrentHashMap<>();
    @PostConstruct
    public void init() {
        // 初始化备份目录
        Path backupPath = Paths.get(backupDir);
        if (!Files.exists(backupPath)) {
            try {
                Files.createDirectories(backupPath);
            } catch (IOException e) {
                throw new RuntimeException("无法创建备份目录", e);
            }
        }
        // 加载已有备份历史
        loadBackupHistory();
        System.out.println("配置备份服务已初始化");
        System.out.println("备份目录: " + backupDir);
        System.out.println("最大备份数: " + maxVersions);
        System.out.println("监控配置文件: " + Arrays.toString(configFiles));
    }
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点备份
    public void scheduledBackup() {
        System.out.println("开始定时备份配置...");
        for (String configFile : configFiles) {
            try {
                ConfigBackup backup = createBackup(configFile);
                System.out.println("备份成功: " + backup.getBackupPath());
                // 清理旧备份
                cleanupOldBackups(configFile);
            } catch (IOException e) {
                System.err.println("备份 " + configFile + " 失败: " + e.getMessage());
            }
        }
    }
    public ConfigBackup createBackup(String configFile) throws IOException {
        Path source = Paths.get(configFile);
        if (!Files.exists(source)) {
            throw new FileNotFoundException("配置文件不存在: " + configFile);
        }
        // 生成备份文件名
        String timestamp = LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_SSS"));
        String backupName = source.getFileName() + ".backup." + timestamp;
        Path backupPath = Paths.get(backupDir, backupName);
        // 执行备份
        Files.copy(source, backupPath, StandardCopyOption.REPLACE_EXISTING);
        // 记录备份历史
        ConfigBackup backup = new ConfigBackup();
        backup.setId(UUID.randomUUID().toString());
        backup.setSourceFile(configFile);
        backup.setBackupPath(backupPath.toString());
        backup.setBackupTime(LocalDateTime.now());
        backup.setFileSize(Files.size(backupPath));
        backup.setMd5(calculateMD5(backupPath.toString()));
        backupHistories.computeIfAbsent(configFile, k -> new ConfigBackupHistory())
                      .addBackup(backup);
        return backup;
    }
    private void cleanupOldBackups(String configFile) {
        ConfigBackupHistory history = backupHistories.get(configFile);
        if (history != null && history.getBackupCount() > maxVersions) {
            List<ConfigBackup> oldBackups = history.getExcessBackups(maxVersions);
            for (ConfigBackup oldBackup : oldBackups) {
                try {
                    Files.deleteIfExists(Paths.get(oldBackup.getBackupPath()));
                    history.removeBackup(oldBackup);
                    System.out.println("已删除过期备份: " + oldBackup.getBackupPath());
                } catch (IOException e) {
                    System.err.println("删除旧备份失败: " + e.getMessage());
                }
            }
        }
    }
    public List<ConfigBackup> getBackupHistory(String configFile) {
        ConfigBackupHistory history = backupHistories.get(configFile);
        return history != null ? history.getBackups() : Collections.emptyList();
    }
    public boolean restoreBackup(String backupId) {
        // 查找备份
        for (ConfigBackupHistory history : backupHistories.values()) {
            ConfigBackup backup = history.findBackup(backupId);
            if (backup != null) {
                try {
                    // 恢复备份前先创建当前配置的备份
                    createBackup(backup.getSourceFile());
                    // 恢复指定的备份
                    Path source = Paths.get(backup.getBackupPath());
                    Path target = Paths.get(backup.getSourceFile());
                    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
                    System.out.println("配置已恢复到: " + backup.getBackupPath());
                    return true;
                } catch (IOException e) {
                    System.err.println("恢复失败: " + e.getMessage());
                    return false;
                }
            }
        }
        return false;
    }
}
// 备份历史记录类
class ConfigBackupHistory {
    private List<ConfigBackup> backups = new ArrayList<>();
    public void addBackup(ConfigBackup backup) {
        backups.add(backup);
        backups.sort(Comparator.comparing(ConfigBackup::getBackupTime).reversed());
    }
    public void removeBackup(ConfigBackup backup) {
        backups.remove(backup);
    }
    public int getBackupCount() {
        return backups.size();
    }
    public List<ConfigBackup> getExcessBackups(int maxSize) {
        if (backups.size() <= maxSize) {
            return Collections.emptyList();
        }
        return backups.subList(maxSize, backups.size());
    }
    public List<ConfigBackup> getBackups() {
        return Collections.unmodifiableList(backups);
    }
    public ConfigBackup findBackup(String backupId) {
        return backups.stream()
            .filter(b -> b.getId().equals(backupId))
            .findFirst()
            .orElse(null);
    }
}
// 备份信息类
class ConfigBackup {
    private String id;
    private String sourceFile;
    private String backupPath;
    private LocalDateTime backupTime;
    private long fileSize;
    private String md5;
    // getters and setters
    // ...
}

REST API 控制器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import java.util.*;
@RestController
@RequestMapping("/api/config-backup")
public class ConfigBackupController {
    @Autowired
    private ConfigBackupService backupService;
    @PostMapping("/backup")
    public ResponseEntity<?> createBackup(@RequestParam String configFile) {
        try {
            ConfigBackup backup = backupService.createBackup(configFile);
            return ResponseEntity.ok(new ApiResponse(true, "备份成功", backup));
        } catch (IOException e) {
            return ResponseEntity.badRequest()
                .body(new ApiResponse(false, "备份失败: " + e.getMessage()));
        }
    }
    @GetMapping("/history")
    public ResponseEntity<?> getBackupHistory(
            @RequestParam(required = false) String configFile) {
        List<ConfigBackup> history;
        if (configFile != null) {
            history = backupService.getBackupHistory(configFile);
        } else {
            // 获取所有配置文件的备份历史
            history = new ArrayList<>();
            // 实现获取所有历史的逻辑
        }
        return ResponseEntity.ok(history);
    }
    @PostMapping("/restore")
    public ResponseEntity<?> restoreBackup(@RequestParam String backupId) {
        boolean success = backupService.restoreBackup(backupId);
        if (success) {
            return ResponseEntity.ok(new ApiResponse(true, "配置恢复成功"));
        } else {
            return ResponseEntity.badRequest()
                .body(new ApiResponse(false, "配置恢复失败"));
        }
    }
    @DeleteMapping("/cleanup")
    public ResponseEntity<?> cleanupOldBackups(@RequestParam String configFile) {
        backupService.cleanupOldBackups(configFile);
        return ResponseEntity.ok(new ApiResponse(true, "旧备份清理完成"));
    }
}
class ApiResponse {
    private boolean success;
    private String message;
    private Object data;
    // 构造函数
    public ApiResponse(boolean success, String message) {
        this.success = success;
        this.message = message;
    }
    public ApiResponse(boolean success, String message, Object data) {
        this.success = success;
        this.message = message;
        this.data = data;
    }
    // getters and setters
    // ...
}

配置文件监控

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
@Component
public class ConfigFileWatcher {
    @Autowired
    private ConfigBackupService backupService;
    @Value("${app.config.watch.enabled:true}")
    private boolean watchEnabled;
    private WatchService watchService;
    @PostConstruct
    public void init() {
        if (watchEnabled) {
            startWatching();
        }
    }
    private void startWatching() {
        try {
            watchService = FileSystems.getDefault().newWatchService();
            Path configDir = Paths.get(".");
            // 注册监控事件
            configDir.register(watchService, 
                ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
            // 启动监控线程
            new Thread(this::watchLoop, "config-watcher").start();
            System.out.println("配置文件监控已启动");
        } catch (IOException e) {
            System.err.println("启动文件监控失败: " + e.getMessage());
        }
    }
    private void watchLoop() {
        while (true) {
            try {
                WatchKey key = watchService.take();
                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    if (kind == OVERFLOW) {
                        continue;
                    }
                    WatchEvent<Path> ev = (WatchEvent<Path>) event;
                    Path fileName = ev.context();
                    // 检查是否是配置文件
                    if (isConfigFile(fileName.toString())) {
                        System.out.println("检测到配置文件变更: " + fileName);
                        // 自动备份
                        try {
                            backupService.createBackup(fileName.toString());
                            System.out.println("自动备份完成");
                        } catch (IOException e) {
                            System.err.println("自动备份失败: " + e.getMessage());
                        }
                    }
                }
                if (!key.reset()) {
                    break;
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    private boolean isConfigFile(String fileName) {
        return fileName.endsWith(".properties") || 
               fileName.endsWith(".yml") || 
               fileName.endsWith(".yaml") ||
               fileName.endsWith(".xml") ||
               fileName.endsWith(".json");
    }
}

配置文件:application.yml

# 配置备份设置
app:
  config:
    backup:
      dir: ./config-backups
      max-versions: 10
      files: 
        - application.properties
        - application.yml
        - logback-spring.xml
    watch:
      enabled: true  # 是否启用文件监控自动备份
# 定时任务设置
spring:
  task:
    scheduling:
      pool:
        size: 5

使用示例

手动备份

# 调用备份API
curl -X POST "http://localhost:8080/api/config-backup/backup?configFile=application.yml"
# 查看备份历史
curl "http://localhost:8080/api/config-backup/history?configFile=application.yml"
# 恢复备份
curl -X POST "http://localhost:8080/api/config-backup/restore?backupId=xxx"

命令行使用

// 直接运行备份工具
public class BackupTool {
    public static void main(String[] args) {
        ConfigBackupService service = new ConfigBackupService();
        service.init();
        // 手动备份
        try {
            service.createBackup("application.properties");
        } catch (IOException e) {
            System.err.println("备份失败: " + e.getMessage());
        }
    }
}

最佳实践建议

  1. 定期备份:设置定时任务(推荐每天)
  2. 版本控制:保留最近N个版本(建议10-30个)
  3. 异地备份:将备份文件同步到远程服务器
  4. 加密传输:备份文件传输时使用SSL/TLS
  5. 完整性验证:使用MD5/SHA256验证备份文件
  6. 灾备恢复:定期测试备份恢复流程

这个案例提供了完整的Java配置备份解决方案,可以根据实际需求进行调整和扩展。

抱歉,评论功能暂时关闭!