APDPlat在数据库备份成功之后,会调用一个系统扩展点,用户可以方便地编写自己的包含特定业务逻辑的插件,并可配置启用哪些插件。本文以将备份文件上传到FTP服务器以实现异地容灾为例子,来说明如何编写自己的插件并配置使其生效。
1、如何编写?
我们先看看系统扩展点,即BackupFileSender接口:
/** * 备份文件发送器 * 将最新的备份文件发送到其他机器,防止服务器故障丢失数据 * @author 杨尚川 */ public interface BackupFileSender { public void send(File file); }
然后新建一个类FtpBackupFileSender,实现系统扩展点:
/** * 将备份文件发送到FTP服务器上面 * @author 杨尚川 */ @Service public class FtpBackupFileSender implements BackupFileSender{ protected final APDPlatLogger LOG = new APDPlatLogger(getClass()); @Resource(name="ftpUtils") private FtpUtils ftpUtils; @Resource(name="configurationEncryptor") private StandardPBEStringEncryptor configurationEncryptor; @Override public void send(File file) { try{ String host = PropertyHolder.getProperty("ftp.server.host"); int port = PropertyHolder.getIntProperty("ftp.server.port"); String username = PropertyHolder.getProperty("ftp.server.username"); String password = PropertyHolder.getProperty("ftp.server.password"); if(username!=null && username.contains("ENC(") && username.contains(")")){ username=username.substring(4,username.length()-1); } if(password!=null && password.contains("ENC(") && password.contains(")")){ password=password.substring(4,password.length()-1); } username = configurationEncryptor.decrypt(username); password = configurationEncryptor.decrypt(password); String dist = PropertyHolder.getProperty("log.backup.file.ftp.dir"); String database = PropertyHolder.getProperty("jpa.database"); dist = dist.replace("${database}", database); LOG.info("本地备份文件:"+file.getAbsolutePath()); LOG.info("FTP服务器目标目录:"+dist); boolean connect = ftpUtils.connect(host, port, username, password); if(connect){ boolean result = ftpUtils.uploadTo(file, dist); if(result){ LOG.info("备份文件上传到FTP服务器成功"); }else{ LOG.error("备份文件上传到FTP服务器失败"); } } }catch(Exception e){ LOG.error("备份文件上传到FTP服务器失败",e); } } }
这里有三个要点:一是跟FTP服务器相关的信息(主机、端口、用户名、密码)从配置文件config.properties或config.local.properties中获取;二是使用FtpUtils的uploadTo方法实现实际的文件上传功能;三是使用StandardPBEStringEncryptor对加密的用户名和密码进行解密(配置文件中不存放明文用户名和密码)。
先看看FTP服务器的配置信息,默认存放在config.properties中,用户可以在config.local.properties中进行重新指定以覆盖默认配置:
ftp.server.host=192.168.0.100 ftp.server.port=21 ftp.server.username=ENC(rAjYIMF6ANd2q/cTgX6SpQ==) ftp.server.password=ENC(GHVWGhan3XajaRZF8QzZKQ==)
接下来看看FtpUtils的实现:
/** * FTP操作工具 * @author 杨尚川 */ @Service public class FtpUtils { protected final APDPlatLogger LOG = new APDPlatLogger(getClass()); private FTPClient ftpClient; /** * 连接FTP服务器 * @param host FTP服务器地址 * @param port FTP服务器端口号 * @param username 用户名 * @param password 密码 * @return */ public boolean connect(String host, int port, String username, String password) { try{ ftpClient = new FTPClient(); ftpClient.connect(host, port); ftpClient.login(username, password); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); LOG.error("连接FTP服务器失败,响应码:"+reply); return false; } }catch(IOException e){ LOG.error("连接FTP服务器失败",e); return false; } return true; } /** * 上传文件到服务器上的特定路径 * @param file 上传的文件或文件夹 * @param path 上传到ftp服务器哪个路径下 * @return */ public boolean uploadTo(File file, String path){ //切换到服务器上面的合适目录 //如果对应的目录不存在,则创建 LOG.info("上传文件 "+file.getAbsolutePath()+" 到服务器路径 "+path); try{ String[] segs = path.split("/"); for(String seg : segs){ if(!ftpClient.changeWorkingDirectory(seg)){ ftpClient.makeDirectory(seg); if(!ftpClient.changeWorkingDirectory(seg)){ LOG.error("服务器目录切换错误:"+seg); return false; } } } }catch(IOException e){ LOG.error("服务器目录切换错误",e); return false; } return upload(file); } /** * 上传文件 * @param file 上传的文件或文件夹 * @return 是否上次成功 */ private boolean upload(File file) { try{ if (file.isDirectory()) { ftpClient.makeDirectory(file.getName()); ftpClient.changeWorkingDirectory(file.getName()); File[] subFiles = file.listFiles(); for (File subFile : subFiles) { if (subFile.isDirectory()) { upload(subFile); ftpClient.changeToParentDirectory(); } else { try (FileInputStream input = new FileInputStream(subFile)) { ftpClient.storeFile(subFile.getName(), input); } } } } else { try (FileInputStream input = new FileInputStream(file)) { ftpClient.storeFile(file.getName(), input); } } }catch(IOException e){ LOG.error("上传文件失败",e); return false; } return true; } }
最后看看解密,StandardPBEStringEncryptor是定义在Spring的配置文件中的,默认加密和解密的密码是config:
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"> <property name="config" ref="environmentVariablesConfiguration" /> </bean> <bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig"> <property name="algorithm" value="PBEWithMD5AndDES" /> <property name="password" value="config" /> </bean>
那么如何对明文的用户名和密码进行加密,然后放入到配置文件中呢?
可以使用APDPlat_Web子项目中的util.ConfigEncryptUtils类来实现:
/** *把密文放到配置文件中的时候要注意: * ENC(密文) * @author 杨尚川 */ public class ConfigEncryptUtils { private static final StandardPBEStringEncryptor ENCRYPTOR = new StandardPBEStringEncryptor(); static{ EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig(); config.setAlgorithm("PBEWithMD5AndDES"); //自己在用的时候更改此密码 config.setPassword("config"); ENCRYPTOR.setConfig(config); } public static void main(String[] args){ String plaintext="test"; String ciphertext=ENCRYPTOR.encrypt(plaintext); System.out.println(plaintext+" : "+ciphertext); } }
在main方法中指定plaintext的值为待加密的字符串,然后运行ConfigEncryptUtils类,控制台输出如下:
test : pXnEaEXPoseN4lSNTuz3eQ==
把密文放到配置文件中的时候要注意,在密文前加入ENC(,在密文后加入),形如ENC(密文),如下所示:
ftp.server.username=ENC(rAjYIMF6ANd2q/cTgX6SpQ==) ftp.server.password=ENC(pXnEaEXPoseN4lSNTuz3eQ==)
2、如何配置?
插件编写完成之后,如何配置使其生效?
在config.local.properties中指定log.backup.file.sender的值为所编写的插件的Spring bean name,可指定多个,用;分割,如下所示:
log.backup.file.sender=ftpBackupFileSender;
相关推荐
【异地容灾备份方案】 异地容灾备份方案是企业为了保障关键数据安全和业务连续性而采取的一种策略。它超越了简单的数据拷贝,涵盖了全面的管理流程,包括备份计划的制定、自动化操作、历史记录保存和日志记录等。在...
数据备份是指异地容灾系统中的一种技术手段,用于备份和恢复数据。实时数据保护是指异地容灾系统中的一种技术手段,用于实时保护数据。数据镜像和数据复制是异地容灾系统中常用的技术手段,用于备份和恢复数据。 ...
异地容灾备份智慧容灾网络安全数据中心方案 异地容灾备份智慧容灾网络安全数据中心方案是指通过建立异地容灾备份中心,以确保数据的安全性和可用性,防止数据丢失或损坏。该方案主要涵盖以下几个方面的知识点: 一...
本案例涉及的是甘肃省电力公司在构建异地容灾系统方面的实践,以确保电力营销管理信息系统的高可用性和安全性。异地容灾系统旨在防止因自然灾害或其他意外事件导致的数据丢失和业务中断,从而减少潜在的经济损失。 ...
爱数备份容灾家族3.5在备份方面支持从Windows到Linux,Unix平台到九大主流数据库的备份,并支持包括操作系统、应用程序、文件系统以及各种虚拟环境的备份。同时,还支持VMware环境下的备份方式VCB(VMware ...
此方案的核心是通过建立本地数据中心和异地容灾中心,结合VERITAS NetBackup软件,实现高效的数据备份、恢复和容灾能力。 首先,本地数据中心配置了一台运行Windows 2000的服务器,安装了VERITAS NetBackup作为主...
异地容灾方案 本文介绍了异地容灾方案,主要介绍了 XIV 存储系统的远程数据复制功能,该功能可以将数据实时地复制到远端的存储系统,从而帮助客户预防机房或整个数据中心可能的灾难场景。 XIV 远程数据复制功能...
异地容灾数据备份解决方案 异地容灾数据备份解决方案是指在灾难发生时,能够快速恢复业务系统的数据备份解决方案。这种解决方案通常用于保护企业的关键业务系统,避免因灾难导致的数据丢失和业务中断。 第一章 ...
容灾系统通常分为多个等级,如国际标准SHARE 78定义的七个层次,从简单的磁带异地备份到实时应用切换的异地备份系统。衡量容灾系统效能的两个关键指标是RPO(Recovery Point Objective)和RTO(Recovery Time ...
Oracle 数据库异地容灾方案是指在两个或多个数据中心之间,使用连续数据复制技术实现数据库的异地容灾备份和恢复。该方案旨在提供高可用性和高可靠性的数据库服务,能够满足企业对数据安全和可用性的要求。 ...
Oracle数据库异地容灾方案是确保企业关键业务系统在面临灾难性事件时,能够迅速恢复运行,保障数据安全和业务连续性的关键策略。本方案旨在提供一套详细的指导,以帮助用户理解如何构建和实施一个有效的Oracle数据库...
微软虚拟化异地容灾解决方案支持多种备份手段,包括文件级备份和镜像级备份。文件级备份针对虚拟机内部的应用和文件,需要代理支持,并可与特定应用(如SQL、Exchange)紧密集成;而镜像级备份则提供了快速的备份与...
2.2.1 数据定期备份系统:数据定期备份系统是异地容灾解决方案的核心组件,负责将数据定期备份到异地存储设备中,以便在出现灾难或系统故障时,能够快速恢复数据。 2.2.2 应用级容灾系统:应用级容灾系统是异地容灾...
本方案旨在提供全面的数据管理和保护策略,涵盖高可用性、远程/异地容灾、数据整合、网络数据备份、零停机备份以及长期归档等关键环节。 一、高可用性 高可用性是确保业务连续性的基础,通过冗余硬件、负载均衡和...
异地容灾备份方案 异地容灾备份方案是指在远程地点对数据进行备份的解决方案,以保障业务系统在灾难情况下的连续性和可靠性。该方案的主要目标是确保业务系统在灾难发生时能够快速恢复,减少业务中断的时间和经济...
爱数备份容灾家族提供了一站式的解决方案,涵盖了从基础的数据备份到高级的应用容灾,以及异地容灾的全部环节。其一体化设计和强大的功能简化了管理和操作,降低了复杂性,确保了企业在面对各种挑战时,能够快速、...
3. 容灾场景简介:阿里云专有云企业版v3.16.2云平台异地容灾用户指南提供了容灾场景简介,包括灾备控制台ASR-DR中的容灾场景简介、跨云容灾场景中的容灾场景简介等内容。 4. 灾备云实例配置:阿里云专有云企业版v...
为了确保基于存储区域网络(Storage Area Network,SAN)的异地容灾系统在主系统发生意外灾难后实现同城异地的数据容灾,采用SAN作为数据存储模式,通过光纤通道将生产数据中心和备份数据中心连接起来,使用跨阵列磁盘镜像...