今天leadr提出需求,原來公司項目中讀取解析xml文件的代碼效率過低,考慮切換一種xml爲數據封裝格式與讀取方式以提升效率。我這靈機一動spring對bean的依賴注入就是讀取xml文件,能夠嘗試扒一扒spring的源碼,來實現一個輕量級的方案。git
重構完成的xml文件格式以下:github
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean name="iaminformation" class="com.whf.readxml.model.IamConfig">
<property name="iamUrl" value="http:192.168.7.154:8080" />
<property name="token" value="abcdefg" />
<property name="iamName" value="中電科" />
<property name="sourceNumber" value="4" />
<property name="timeSpan" value="12" />
</bean>
<bean name="plugin" class="com.whf.readxml.model.PluginAttributes">
<property name="name" value="ADTest1" />
<property name="pluginType" value="AdPlugin" />
<property name="code" value="100001" />
<property name="url" value="ldap://192.168.7.241:389" />
<property name="adminPsw" value="1qaz2wsx2017" />
<property name="adminName" value="QUARKDATA\administrator" />
<property name="adDn" value="OU=test,DC=quarkdata,DC=com" />
<property name="securityAuthentication" value="simple" />
<property name="staffFieldMatch">
<bean name="staffFieldMatch" class="com.whf.readxml.model.StaffFieldMatch">
<property name="idField" value="objectGUID" />
<property name="userNameField" value="sAMAccountName" />
<property name="firstNameField" value="givenName" />
<property name="lastNameField" value="sn" />
<property name="displayNameField" value="displayName" />
<property name="phoneNumberField" value="" />
<property name="telField" value="homePhone" />
<property name="emailField" value="email" />
</bean>
</property>
<property name="orgFieldMatch">
<bean name="orgFieldMatch" class="com.whf.readxml.model.OrgFieldMatch">
<property name="idField" value="objectGUID" />
<property name="nameField" value="name" />
<property name="displayNameField" value="ou" />
</bean>
</property>
<property name="groupFieldMatch">
<bean name="groupFieldMatch" class="com.whf.readxml.model.GroupFieldMatch">
<property name="idFied" value="objectGUID" />
<property name="nameField" value="sAMAccountName" />
<property name="displayNameField" value="displayName" />
<property name="decriptionField" value="info" />
</bean>
</property>
</bean>
<bean name="plugin" class="com.whf.readxml.model.PluginAttributes">
<property name="name" value="LDAPTest1" />
<property name="pluginType" value="LdapPlugin" />
<property name="code" value="100002" />
<property name="url" value="ldap://192.168.7.245/" />
<property name="adminPsw" value="test123456" />
<property name="adminName" value="cn=admin,dc=thundersoft,dc=com" />
<property name="adDn" value="dc=thundersoft,dc=com" />
<property name="securityAuthentication" value="simple" />
<property name="staffFieldMatch">
<bean name="staffFieldMatch" class="com.whf.readxml.model.StaffFieldMatch">
<property name="idField" value="gidNumber" />
<property name="userNameField" value="uid" />
<property name="firstNameField" value="givenName" />
<property name="lastNameField" value="sn" />
<property name="displayNameField" value="displayName" />
<property name="phoneNumberField" value="telephoneNumber" />
<property name="telField" value="tel" />
<property name="emailField" value="email" />
</bean>
</property>
<property name="orgFieldMatch">
<bean name="orgFieldMatch" class="com.whf.readxml.model.OrgFieldMatch">
<property name="idField" value="dn" />
<property name="nameField" value="ou" />
<property name="displayNameField" value="orgDisplayName" />
</bean>
</property>
<property name="groupFieldMatch">
<bean name="groupFieldMatch" class="com.whf.readxml.model.GroupFieldMatch">
<property name="idFied" value="dn" />
<property name="nameField" value="cn" />
<property name="displayNameField" value="groupDisplayName" />
<property name="decriptionField" value="description" />
</bean>
</property>
</bean>
</beans>複製代碼
看起來很眼熟的有沒有,跟spring的配置文件同樣哦。spring
手動扒了一下spring讀取xml文件的代碼,因爲spring過於龐大,讀取spring的xml方法又按照讀取不一樣的標籤被分拆出n多個方法,樓主能力有限就不在這裏賣弄了,不過spring從配置文件把bean加載到bean工廠跟樓主下面讀取xml文件的方式理論上是同樣的。bash
廢話很少說,上代碼:框架
/**
* 模擬spring依賴注入的方式讀取xml文件.
* @author whf
* @date Aug 23, 2017
*/
public class XMLBeanFactory {
private String xmlName;
private SAXReader reader;
private Document document;
/**
* 構造方法.
* @param xmlName xmlName.
*/
public XMLBeanFactory(String xmlName) { // 在構造方法中
try {
this.xmlName = xmlName;
reader = new SAXReader();
document = reader.read(this.getClass().getClassLoader().getResourceAsStream(xmlName));
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 獲取相同類型的bean.
* @param type bean的class type.
* @return 返回相同類型的bean的list.
* @throws Exception Exception.
*/
public <T> List<T> getBeansOfType(Class<T> type) throws Exception {
List<T> objects = new ArrayList<>();
try {
Element root = document.getRootElement();
List<Element> beans = root.elements();
if (beans.size() > 0) {
for (Element bean : beans) {
if (bean.attributeValue("class").equals(type.getName())) {
T object = null;
String clazz = bean.attributeValue("class");
// 經過反射來建立對象
Class beanClass = Class.forName(clazz);
object = (T) beanClass.newInstance();
List<Element> propertys = bean.elements();
if (propertys.size() > 0) {
for (Element property : propertys) {
String key = property.attributeValue("name");
Field field = beanClass.getDeclaredField(key);
field.setAccessible(true);
List<Element> childBean = property.elements();
// 若是property下內嵌bean
if (childBean.size() > 0) {
Object childObject = getBean(key, property);
field.set(object, childObject);
} else {
/*
* 此屬性值是一個字符串.這裏單獨處理int,float類型變量.若是不處理,
* 會將String類型直接賦值給int類型,發生ClassCastException
*/
String value = property.attributeValue("value");
// 須要對類型進行判斷
if (field.getType().getName().equals("int")) {
// 整數
int x = Integer.parseInt(value);
field.set(object, x);
continue;
}
if (field.getType().getName().equals("float")) {
// 浮點數
float y = Float.parseFloat(value);
field.set(object, y); // 注意double能夠接受float類型
continue;
}
field.set(object, value);// 處理String類型
}
}
}
objects.add(object);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return objects;
}
/**
* 獲取property內嵌的bean.
* @param name id或者bean的name
* @param root 根節點.
* @return 返回封裝完整的bean.
* @throws Exception Exception.
*/
public Object getBean(String name, Element root) throws Exception {
Object object = null;
List<Element> beans = root.elements();
if (beans.size() > 0) {
for (Element bean : beans) {
if (bean.attributeValue("name").equals(name)) {
// 若是bean name相同則開始建立對象
String clazz = bean.attributeValue("class");
// 經過反射來建立對象
Class beanClass = Class.forName(clazz);
object = beanClass.newInstance();
List<Element> propertys = bean.elements();
if (propertys.size() > 0) {
for (Element property : propertys) {
String key = property.attributeValue("name");
Field field = beanClass.getDeclaredField(key);
field.setAccessible(true);
List<Element> childBean = property.elements();
// 若是property下內嵌bean
if (childBean.size() > 0) {
field.set(object, getBean(key, property));
}
if (property.attribute("ref") != null) {
/*
* 此屬性的值是一個對象.這裏因爲直接調用getBean方法賦值給對象,返回的對象必定是Bean參數的對象, 所以強制轉換不會出問題
*/
String refid = property.attributeValue("ref");
field.set(object, getBean(refid));
} else {
/*
* 此屬性值是一個字符串.這裏單獨處理int,float類型變量.若是不處理,會將String類型直接賦值給int類型,
* 發生ClassCastException
*/
String value = property.attributeValue("value");
// 須要對類型進行判斷
field.set(object, value);// 處理String類型
}
}
}
}
}
}
return object;
}
}複製代碼
樓主的代碼就是實現讀取xml文件中相同類型的bean封裝到list中返回。具體如何實現,看代碼,註釋寫的很清楚了。ui
代碼完成以後,對比以前的讀取xml的代碼,比以前的效率提高了120。this
大牛都說要看開源框架的源碼,收穫會怎樣怎樣,可是對於大部分向我這樣的僞碼農去扒源碼的時候老是一頭霧水,不知所云。然而,當咱們真正有需求的時候,開源代碼的實現便成了一份巨大的寶藏,帶着咱們的目的去扒源碼,有時候會有事半功倍的效果。樓主親測有效,源碼雖好,可不要貪杯哦。url
文章出處: blog.csdn.net/github_3637…spa