2021SC@SDUSC
在上篇文章中,我们分析了performImport方法中使用Simple框架序列化Java Bean对象的部分,在本篇文章中我们将对performImport方法中剩下的代码进行分析。
performImport
本篇文章要分析的performImport代码
// BackupImport.java
public void performImport(InputStream is) throws Exception {
...
// 上面的代码已经分析过,就省略
BackupVersion ver = getVersion(simpleSerializer, f);
importConfigs(f);
...
}
BackupVersion
// BackupImport.java
private static BackupVersion getVersion(Serializer ser, File f) throws Exception {
List<BackupVersion> list = readList(ser, f, "version.xml", "version", BackupVersion.class, null, true);
// 判断list是否为空,若空,则新建一个BackupVersion对象,否则,取列表的第一个元素作为返回值
return list.isEmpty() ? new BackupVersion() : list.get(0);
}
// 来看一下getVersion中的readList方法,该方法也在该类中
private static <T> List<T> readList(Serializer ser, File baseDir, String fileName, String listNodeName, Class<T> clazz, BiConsumer<InputNode, T> consumer, boolean notThow) throws Exception {
List<T> list = new ArrayList<>();
// 读取version.xml文件
File xml = new File(baseDir, fileName);
if (!xml.exists()) {
final String msg = fileName + " missing";
if (notThow) {
log.debug(msg);
return list;
} else {
throw new BackupException(msg);
}
}
// 根据读取的xml文件创建2个输入流
try (InputStream rootIs1 = new FileInputStream(xml); InputStream rootIs2 = new FileInputStream(xml)) {
/* InputNode、NodeBuilder来自simple框架 */
/*
NodeBuilder对象用于为给定的源或目标创建输入节点或输出节点。
如果读取XML文档需要InputNode,那么必须提供读取器来读取其中的内容。
*/
/*
InputNode对象表示元素中元素的迭代器。
这允许输入节点对象成为元素及其子元素的自包含迭代器。
从输入节点对象中获取的每一个子节点本身就是一个输入节点,可以用来探索其子元素,而不会对其外部元素产生任何影响。
*/
InputNode root1 = NodeBuilder.read(rootIs1);
InputNode root2 = NodeBuilder.read(rootIs2); // for various hacks
// getNext():返回该元素的子元素
InputNode listNode1 = root1.getNext();
InputNode listNode2 = root2.getNext(); // for various hacks
if (listNodeName.equals(listNode1.getName())) {
InputNode item1 = listNode1.getNext();
while (item1 != null) {
/*
<T> T read(Class<? extends T> type,Reader source,boolean strict) throws Exception
这个read方法将从提供的源读取XML文档的内容,并将其转换为指定类型的对象。
如果XML源不能反序列化,或者在构建对象图时出现问题,则会引发异常。
返回反序列化的实例。
参数:
type:这是要从XML反序列化的类类型
source:提供xml文档的源
strict:决定是否在严格模式下读取
在这里即表示不在严格模式下将version.xml文档反序列化为BackupVersion类对象
*/
T o = ser.read(clazz, item1, false);;
if (consumer != null) {
consumer.accept(listNode2, o);
}
// 把反序列后的对象放入列表中
list.add(o);
// 遍历下一个子元素
item1 = listNode1.getNext();
}
}
}
// 最终会得到一个version.xml文档反序列化后的BackupVersion对象列表
return list;
}
importConfigs
// BackupImport.java
private void importConfigs(File f) throws Exception {
Registry registry = new Registry();
Strategy strategy = new RegistryStrategy(registry);
RegistryMatcher matcher = new RegistryMatcher();
Serializer serializer = new Persister(strategy, matcher);
matcher.bind(Long.class, LongTransform.class);
registry.bind(Date.class, DateConverter.class);
registry.bind(User.class, new UserConverter(userDao, userMap));
// Configuration类来自openmeetings-db包,不属于我的分析范围,在这里就不展开分析了
List<Configuration> list = readList(serializer, f, "configs.xml", "configs", Configuration.class, null, true);
// 以上内容和我们之前在performImport方法中分析过的代码很像,在这里是对configs.xml文件进行反序列化,得到一个包含Configuration对象的列表
for (Configuration c : list) {
if (c.getKey() == null || c.isDeleted()) {
continue;
}
String newKey = outdatedConfigKeys.get(c.getKey());
if (newKey != null) {
c.setKey(newKey);
}
Configuration.Type type = configTypes.get(c.getKey());
if (type != null) {
c.setType(type);
if (Configuration.Type.bool == type) {
c.setValue(String.valueOf("1".equals(c.getValue()) || "yes".equals(c.getValue()) || "true".equals(c.getValue())));
}
}
// 根据key值检索配置
Configuration cfg = cfgDao.forceGet(c.getKey());
if (cfg != null && !cfg.isDeleted()) {
log.warn("Non deleted configuration with same key is found! old value: {}, new value: {}", cfg.getValue(), c.getValue());
}
c.setId(cfg == null ? null : cfg.getId());
if (c.getUser() != null && c.getUser().getId() == null) {
c.setUser(null);
}
if (CONFIG_CRYPT.equals(c.getKey())) {
try {
Class<?> clazz = Class.forName(c.getValue());
// getDeclaredConstructor返回一个构造函数对象
// newInstance使用此构造函数创建和初始化构造函数所声明类的新实例。
clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
log.warn("Not existing Crypt class found {}, replacing with SCryptImplementation", c.getValue());
c.setValue(SCryptImplementation.class.getCanonicalName());
}
}
// 更新数据库
cfgDao.update(c, null);
}
}
总结
在本篇文章中,分析了2行代码:
BackupVersion ver = getVersion(simpleSerializer, f);
importConfigs(f);
分析这部分代码时,也分析到了涉及的getVersion、readList方法。在readList方法和importConfigs方法中都涉及到了上篇文章分析的simple框架,理解需要一定的时间。performImport方法后面还有很多的import方法,其作用应该和importConfigs大同小异,都是引入相关的配置、资源等等。performImport方法中的内容比较多,也涉及到很多其他的方法,逐一分析耗时较长,还需以后慢慢理解、慢慢钻研。