項目源代碼可訪問我的github:https://github.com/Spacider/Gather-and-store
如果覺得好的話請給個star哦~
開發IDE: IDEA 2018.03 JDK 1.8
開發環境: macOS 10.13.6 (如windows請對項目中部分路徑進行改寫)
數據庫: Oracle 11g
上節完畢項目主體已經基本開發完成,下列進行一系列優化操作:
1.備份模塊:
先編寫一個接口:
/**
* 備份模塊
* 1. 客戶端發送集合沒有發送出去或連不上服務器需要備份
* 2. 服務端接收了集合對象寫入數據庫出錯,對集合進行備份
*/
public interface BackUp extends WossModel{
/**
* 將集合保存到文件中
* @param coll 需要備份的集合
*/
void storeEnvs(Collection<Environment> coll );
/**
* 將集合從文件中讀取
* @return
*/
Collection<Environment> loadEnvs();
}
具體實現:
通過對象流套文件流的形式把對象存入備份文件中:
@Override
public void storeEnvs(Collection<Environment> coll) {
File file = new File(path);
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
if (!file.exists()) {
file.createNewFile();
}
fos = new FileOutputStream(file,true);
oos = new ObjectOutputStream(fos);
oos.writeObject(coll);
oos.flush();
System.out.println("已經存入備份文件中 ,path:" +path);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtil.close(fos,oos);
}
}
從備份文件中取出相應對象!
@Override
public Collection <Environment> loadEnvs() {
FileInputStream fis = null;
ObjectInputStream ois = null;
Object backupObject = null;
try {
fis = new FileInputStream(path);
ois = new ObjectInputStream(fis);
backupObject = ois.readObject();
// System.out.println("已經從 path:" + path + "取出備份文件");
log.info("從 path:" + path + "取出備份文件中...");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return (Collection <Environment>) backupObject;
}
2.日誌模塊
先編寫一個接口叫Log
,裏邊封裝了日誌的四種級別:
public interface Log extends WossModel{
/**
* 輸出 debug 級別的日誌
* @param msg
*/
void debug(String msg);
/**
* 輸出 info 級別的日誌
* @param msg
*/
void info(String msg);
/**
* 輸出 warn 級別的日誌
* @param msg
*/
void warn(String msg);
/**
* 輸出 error 級別的日誌
* @param msg
*/
void error(String msg);
}
日誌模塊的實現就是調用log4j的日誌配置,然後做對應的輸出:
private Logger LOGGER = Logger.getLogger(LogImpl.class);
public LogImpl() {
PropertyConfigurator.configure("/Users/wjh/Desktop/FirstProject/src/main/resources/log4j.properties");
}
@Override
public void debug(String msg) {
LOGGER.debug(msg);
}
@Override
public void info(String msg) {
LOGGER.info(msg);
}
@Override
public void warn(String msg) {
LOGGER.warn(msg);
}
@Override
public void error(String msg) {
LOGGER.error(msg);
}
@Override
public void init(Properties properties) {
}
3.配置模塊
首先配置一個接口爲WossModel
,裏面有一個方法,有了這個方法之後當一個類如果實現了這個接口,我們就可以把Properties
文件傳給它,在Properties
文件中我們又可以傳入相應的參數,這樣做可以靈活替換類中的可變參,讓整個程序變得靈活起來!
/**
* 初始化配置參數
*/
public interface WossModel {
void init(Properties properties);
}
再定義一個接口爲Configuration
,在這個接口的實現中會通過反射去獲取各個類(又可以說是一個模塊)的對象,保證了對象的唯一性!這一部分又可以看做是一個注入過程,讓對象的創建變得靈活,變得安全!
/**
* 獲取各個配置模塊對象
* 對所有對象進行管理
*/
public interface Configuration {
/**
* 獲取採集模塊對象
*/
Gather getGather();
/**
* 獲取客戶端模塊對象
*/
EnvClient getClient();
/**
* 獲取服務器端對象
*/
EnvServer getServer();
/**
* 獲取入庫模塊對象
*/
DBStore getDBStore();
/**
* 獲取日誌模塊對象
*/
Log getLog();
/**
* 獲取備份模塊對象
*/
BackUp getBackUp();
}
最後一個接口是ConfigurationAware
,這個接口的主要用途就是當遇到一個模塊對象調用到另一個模塊對象時間,就可以把剛纔寫的Configuration
整個注入進去,有了這個Configuration
對象就相當於可以獲取到了其他所有配置模塊的對象,這樣你就可以靈活去獲取到你需要的對象並且調用其內的方法了!
public interface ConfigurationAware {
void SetConfiguration(Configuration conf);
}
具體實施
講了這麼多,具體咋實施呢:
給你需要的類上接口!
例如:
客戶端的類:
讓接口實現WossModel
接口,那麼子實現就默認也實現了這個接口!
由於在客戶端類中
public interface EnvClient extends WossModel {
}
public class EnvClientImpl implements EnvClient , ConfigurationAware {
}
當繼承了WossModel
接口之後我們就可以實現其方法來接入Properties
文件:
public void init(Properties properties) {
port = Integer.parseInt(properties.getProperty("port"));
}
這樣我們就可以替換掉port
屬性,等會有寫怎樣去通過寫入XML文件的形式讀取到這個port屬性!
最後是重頭戲,實現Configuration
類,編寫ConfigurationImpl
類:
按照如下形式去
<?xml version="1.0" encoding="UTF-8" ?>
<EMS>
<Log class="com.briup.util.Impl.LogImpl">
</Log>
<gather class="com.briup.Client.Impl.GatherImpl">
<logFile>/Users/wjh/Desktop/FirstProject/src/radwtmp</logFile>
<positionFile>/Users/wjh/Desktop/FirstProject/src/main/resources/FilePostion.properties</positionFile>
</gather>
<EnvClient class = "com.briup.Client.Impl.EnvClientImpl">
<host>127.0.0.1</host>
<port>9999</port>
<path>/Users/wjh/Desktop/FirstProject/src/BackUptmp</path>
</EnvClient>
<EnvServer class="com.briup.Server.Impl.EnvServerImpl">
<port>9999</port>
</EnvServer>
<BackUp class="com.briup.util.Impl.BackUpImpl">
<BackUppath>/Users/wjh/Desktop/FirstProject/src/BackUptmp</BackUppath>
</BackUp>
<DBStore class="com.briup.Server.Impl.DBStoreImpl">
</DBStore>
</EMS>
以
<對象名 class="對象的全限定名">
<需要替換的屬性名>屬性值</需要替換的屬性名>
</對象名>
來進行編寫
在ConfigurationImpl
的構造器中,編寫對XML文件進行解析的代碼!
這裏還是用之前用到的Dom4j,先獲取到根節點,然後獲取最大的子節點,也就是對象名
fis = new FileInputStream("/Users/wjh/Desktop/FirstProject/src/main/resources/EMS.xml");
document = saxReader.read(fis);
EMS = document.getRootElement();
List<Element> EMSlist = EMS.elements();
使用一個map集合來存儲我們得到的對象:
// 使用 Map 集合來存放 模塊名-對象
private Map<String,WossModel> ObjectMap = new HashMap <>();
再遍歷對象名的時候,獲取對象名的class屬性,也就是全限定名,通過Class.forName()
來獲取到的對應的對象,然後存入map集合中,然後繼續遍歷下一層,碰到有需要可變參數的模塊的時候把可變參數提取出來,交給Properties
,等待對象成功創建以後通過其中的init
方法把Properties
對象傳入,最後如果遇到了類繼承了ConfigurationAware
接口(也就是說這個類會調用其他類的對象),就調用SetConfiguration
方法把Configuration
對象傳入!這樣就可以在一個類中去調用其他類的對象了:
for (Element element : EMSlist){
//gather -- EnvClient -- EnvServer -- BackUp -- DBStore --
String elementName = element.getName();
String elementClass = element.attribute("class").getText();
WossModel obj = (WossModel) Class.forName(elementClass).newInstance();
if (obj instanceof ConfigurationAware){
((ConfigurationAware) obj).SetConfiguration(this);
}
// 遍歷子節點,爲應該賦值的變量賦值
List<Element> ChildEMSList = element.elements();
Properties properties =new Properties();
for (Element element1 : ChildEMSList){
properties.setProperty(element1.getName(),element1.getText());
}
// 調用其 init 方法,對變量進行賦值
obj.init(properties);
ObjectMap.put(elementName,obj);
}
當做完了這一切,對象的創建變得異常簡單:
@Override
public Gather getGather() {
return (Gather) ObjectMap.get("gather");
}
@Override
public EnvClient getClient() {
return (EnvClient) ObjectMap.get("EnvClient");
}
@Override
public EnvServer getServer() {
return (EnvServer) ObjectMap.get("EnvServer");
}
@Override
public DBStore getDBStore() {
return (DBStore) ObjectMap.get("DBStore");
}
@Override
public Log getLog() {
return (Log) ObjectMap.get("Log");
}
@Override
public BackUp getBackUp() {
return (BackUp) ObjectMap.get("BackUp");
}
在配置模塊之後,就可以通過這樣來創造一個新的對象:
ConfigurationImpl configuration = new ConfigurationImpl();
Gather gather = configuration.getGather();
而在繼承了ConfigurationAware
接口的類中,可以通過
private Configuration configuration;
private Log logger;
@Override
public void SetConfiguration(Configuration conf) {
this.configuration = conf;
logger = configuration.getLog();
}
日誌也變得如此簡單:
logger.info("插入數據庫成功:" + count + "數據");
logger.error("插入數據庫失敗");
項目的說明就此結束,項目的說明中的代碼不一定完整,完整代碼在 https://github.com/Spacider/Gather-and-store
這是一個練手項目,通過這個項目你可以對java基礎有更深層次的瞭解,其中運用了注入,模塊分割等常用的方法,使你之後對spring等框架的理解更深一個層次!
本人語言溝通能力尚缺,可能講的地方會出問題,請指教!希望能和大家一起學習,一起進步!
個人網站:http://www.spacider.com/
CSDN:https://blog.csdn.net/qq_37163479
聯繫QQ:729215049