Take a look at spring, dom4j implements simulation to read xml

Today, the leader put forward a request. The code efficiency of reading and parsing xml files in the company's project was too low. Consider switching an xml to the data encapsulation format and reading method to improve efficiency. I got the idea that spring's dependency injection on beans is to read xml files. I can try to dig through the source code of spring to implement a lightweight solution.

Refactor the xml file to align with spring's xml file format

The format of the refactored xml file is as follows:

<?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>

Does it look familiar? It's the same as spring's configuration file.

Take a look at the source code of spring to read the xml file

I manually picked up the code for spring to read xml files. Because spring is too large, the xml method of reading spring is divided into n methods according to different tags. The landlord's ability is limited, so I won't show it here, but spring Loading beans from the configuration file into the bean factory is theoretically the same as the way the landlord reads the xml file.

Without further ado, here is the code:

/**
 * 模拟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;
    }

}

The landlord's code is to read the bean of the same type in the xml file and encapsulate it into the list for return. Specifically how to achieve, look at the code, the comments are very clear.

The efficiency of file reading is increased by more than 120 times

After the code is completed, compared with the previous code for reading xml, the efficiency is improved by 120.

in conclusion

Daniel said that depending on the source code of the open source framework, what will happen to the harvest, but most of the pseudo-code farmers like me are always confused when they go to the source code and don't know what to say. However, when we really need it, the implementation of open source code has become a huge treasure. Going to the source code with our purpose sometimes has the effect of getting twice the result with half the effort. The landlord's personal test is effective, although the source code is good, don't be greedy.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325949721&siteId=291194637