扒一扒spring,dom4j实现模拟实现读取xml
今天leadr提出需求,原来公司项目中读取解析xml文件的代码效率太低,考虑切换一种xml为数据封装格式与读取方式以提高效率。我这灵机一动spring对bean的依赖注入就是读取xml文件,可以尝试扒一扒spring的源码,来实现一个轻量级的方案。
重构xml文件,向spring的xml文件格式看齐
重构完成的xml文件格式如下:
<?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读取xml文件的源码
手动扒了一下spring读取xml文件的代码,由于spring过于庞大,读取spring的xml方法又按照读取不同的标签被分拆出n多个方法,楼主能力有限就不在这里卖弄了,不过spring从配置文件把bean加载到bean工厂跟楼主下面读取xml文件的方式理论上是一样的。
废话不多说,上代码:
/**
* 模拟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中返回。具体如何实现,看代码,注释写的很清楚了。
文件读取的效率提升120多倍
代码完成之后,对比之前的读取xml的代码,比之前的效率提升了120。
总结一下
大牛都说要看开源框架的源码,收获会怎样怎样,但是对于大部分向我这样的伪码农去扒源码的时候总是一头雾水,不知所云。然而,当我们真正有需求的时候,开源代码的实现便成了一份巨大的宝藏,带着我们的目的去扒源码,有时候会有事半功倍的效果。楼主亲测有效,源码虽好,可不要贪杯哦。
扒一扒spring,dom4j实现模拟实现读取xml的更多相关文章
- Dom4j使用Xpath语法读取xml节点
我们可以使用Xpath的语法来轻易的读取xml的某个节点[类似于jQuery的选择器]: 使用Xpath语法需要添加新的jaxen-1.1-beta-7.rar 这个jar包 dom4j完整jar包我 ...
- 菜鸟学Java(八)——dom4j详解之读取XML文件
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...
- spring源码系列(十): 读取xml入口类 ClassPathXmlApplicationContext 分析
环境准备: 使用spring5.1.6版本 1 xml配置文件 <?xml version="1.0" encoding="UTF-8"?> < ...
- Spring相关:jdom学习:读取xml文件
云课堂马士兵的spring2.5课程中提到的 用JDOM读取XML文件需先用org.jdom.input.SAXBuilder对象的build()方法创建Document对象,然后用Document类 ...
- DOM4J 读取XML配置文件进行数据库连接
介绍介绍DOM4J. 据说是非常优秀非常优秀的Java XML API(Dom4j is an easy to use, open source library for working ...
- 扒一扒@Retryable注解,很优雅,有点意思!
你好呀,我是歪歪. 前几天我 Review 代码的时候发现项目里面有一坨逻辑写的非常的不好,一眼望去简直就是丑陋之极. 我都不知道为什么会有这样的代码存在项目里面,于是我看了一眼提交记录准备叫对应的同 ...
- linux2.6.24内核源代码分析(2)——扒一扒网络数据包在链路层的流向路径之一
在2.6.24内核中链路层接收网络数据包出现了两种方法,第一种是传统方法,利用中断来接收网络数据包,适用于低速设备:第二种是New Api(简称NAPI)方法,利用了中断+轮询的方法来接收网络数据包, ...
- linux2.6.24内核源代码分析(1)——扒一扒sk_buff
最近研究了linux内核的网络子系统上的网络分组的接收与发送的流程,发现这个叫sk_buff的东西无处不在,内核利用了这个结构来管理分组,在各个层中传递这个结构,因此sk_buff可以说是linux内 ...
- Spring依赖注入 --- 模拟实现
Spring依赖注入 --- 模拟实现 面向接口编程,又称面向抽象编程, 数据库如果发生更改,对应的数据访问层也应该改变多写几个实现,需要用谁的时候在service里new谁就可以了面向抽象编程的好处 ...
随机推荐
- VS2005环境下的DLL应用
VS2005环境下的DLL应用 作者:一点一滴的Beer http://beer.cnblogs.com/ 以前写过一篇题为<VC++的DLL应用(含Demo演示)>的文章,当时是刚开始接 ...
- 在linux里建立一个快捷方式,连接到另一个目录
ln -s 源目录 目标快捷方式比如要在/home/下面建立一个叫WIN7的快捷方式,指向/mnt/:ln -s /home/WIN7 /mnt
- ipad与iphone的屏幕分辨率
1.ipad分辨率,iphone 6 iPhone设备 尺寸 分辨率 点iPhone 3和3s 3.5英寸 (320×480) 3 ...
- 接口方式[推荐]/动态SQL语句
MVC目录结构: Src -- com.shxt.servlet[控制层] --com.shxt.service[业务逻辑层] --com.shxt.model[实体Bean,用来承载数据] --co ...
- GWT异步更改cellTable中cell的数据显示
项目中遇到一个棘手的问题,使用GWT的cellTable的时候,要更改一个单元格的显示问题.如果仅仅是一个单独的cell 可能会有比较好的处理办法,比如可以找到这一列,然后更新整个cellTable, ...
- 第一个springboot项目
公司最近的项目在使用springboot和springcloud中的一些组件,刚开始就是主要写一些业务代码,并不了解具体要去怎么配置等,所以最近刚好有时间,就学习学习,记录总结一下,初学,欢迎指正. ...
- Profile配置
Profile是Spring用来针对不同环境对不同的配置提供支持的,全局Profile配置使用application-{profile}.properties application.properti ...
- Codeforces Round #310 (Div. 2)556ABCDE
https://github.com/Anoxxx/OI/blob/master/Anoxx/Contest10 github自取
- 问题:oracle字符串函数;结果:Oracle字符串函数
Oracle字符串函数 最近换了新公司,又用回Oracle数据库了,很多东西都忘记了,只是有个印象,这两晚抽了点时间,把oracle对字符串的一些处理函数做了一下整理,供日后查看.. 平常我们用Ora ...
- XSS过滤器的实现
一.XSS是什么 全称跨站脚本(cross site script)XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去.使别的用户访问 ...