创建一个JAXB Unmarshaller池

9
我正在寻找一种方法来改善JAXB反编组处理大量文件集的性能,并发现了以下建议:
“如果您真的关心性能,和/或您的应用程序将读取许多小型文档,则创建Unmarshaller可能是相对昂贵的操作。在这种情况下,请考虑池化Unmarshaller对象。”
在网上搜索示例并没有返回任何内容,因此我认为在此使用Spring 3.0和Apache Commons Pool实现我的实现可能会有兴趣。
UnmarshallerFactory.java
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.springframework.stereotype.Component;

/**
 * Pool of JAXB Unmarshallers.
 * 
 */
@Component
public class UnmarshallerFactory implements KeyedPoolableObjectFactory {
    // Map of JAXB Contexts
    @SuppressWarnings("rawtypes")
    private final static Map<Object, JAXBContext> JAXB_CONTEXT_MAP = new HashMap<Object, JAXBContext>();

    @Override
    public void activateObject(final Object arg0, final Object arg1) throws Exception {
    }

    @Override
    public void passivateObject(final Object arg0, final Object arg1) throws Exception {
    }

    @Override
    public final void destroyObject(final Object key, final Object object) throws Exception {
    }

    /**
     * Create a new instance of Unmarshaller if none exists for the specified
     * key.
     * 
     * @param unmarshallerKey
     *            : Class used to create an instance of Unmarshaller
     */
    @SuppressWarnings("rawtypes")
    @Override
    public final Object makeObject(final Object unmarshallerKey) {
        if (unmarshallerKey instanceof Class) {
            Class clazz = (Class) unmarshallerKey;
            // Retrieve or create a JACBContext for this key
            JAXBContext jc = JAXB_CONTEXT_MAP.get(unmarshallerKey);
            if (jc == null) {
                try {
                    jc = JAXBContext.newInstance(clazz);
                    // JAXB Context is threadsafe, it can be reused, so let's store it for later
                    JAXB_CONTEXT_MAP.put(unmarshallerKey, jc);
                } catch (JAXBException e) {
                    // Deal with that error here
                    return null;
                }
            }
            try {
                return jc.createUnmarshaller();
            } catch (JAXBException e) {
                // Deal with that error here
            }
        }
        return null;
    }

    @Override
    public final boolean validateObject(final Object key, final Object object) {
        return true;
    }
}

UnmarshallerPool.java

import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UnmarshallerPool extends GenericKeyedObjectPool {
    @Autowired
    public UnmarshallerPool(final UnmarshallerFactory unmarshallerFactory) {
    // Make usage of the factory created above
    super(unmarshallerFactory);
            // You'd better set the properties from a file here
    this.setMaxIdle(4);
    this.setMaxActive(5);
    this.setMinEvictableIdleTimeMillis(30000);
    this.setTestOnBorrow(false);
    this.setMaxWait(1000);
    }

    public UnmarshallerPool(UnmarshallerFactory objFactory,
        GenericKeyedObjectPool.Config config) {
        super(objFactory, config);
    }

    @Override
    public Object borrowObject(Object key) throws Exception {
        return super.borrowObject(key);
    }

    @Override
    public void returnObject(Object key, Object obj) throws Exception {
        super.returnObject(key, obj);
    }
}

如果你的类需要一个JAXB Unmarshaller:

    // Autowiring of the Pool
    @Resource(name = "unmarshallerPool")
    private UnmarshallerPool unmarshallerPool;

    public void myMethod() {
        Unmarshaller u = null;
        try {
            // Borrow an Unmarshaller from the pool
            u = (Unmarshaller) this.unmarshallerPool.borrowObject(MyJAXBClass.class);
            MyJAXBClass myJAXBObject = (MyJAXBClass) u.unmarshal(url);
            // Do whatever
        } catch (Exception e) {
            // Deal with that error
        } finally {
            try {
                // Return the Unmarshaller to the pool
                this.unmarshallerPool.returnObject(MyJAXBClass.class, u);
            } catch (Exception ignore) {
            }
        }
    }

这个示例有些幼稚,因为它仅使用一个类来创建JAXBContext,并将同一个类实例作为键传递给键池。可以通过传递一个类数组作为参数而不仅仅是一个类来改进它。

希望这能有所帮助。


3
嗯……这不是一个问题…… - lscoughlin
1
我不知道如何创建一个不是问题的主题。 - Bruno Chauvet
嗨,Hut。我认为这很有价值,SO允许“回答自己的问题”,也许你可以将帖子重新构建成一个问题,并提供你的实现作为“答案”,然后你可以接受它。 - Brett Ryan
1
这可能有点老了,但看起来是一个非常好的方法。http://axixmiqui.wordpress.com/2009/09/01/spring-injecting-jaxb-unmarshaller/ - Kurt Madel
1个回答

1

创建反序列化器的目的是为了轻量级。在开发池策略之前,建议进行一些分析。


6
正如我所说,这全部基于此处找到的建议:<a href="http://jaxb.java.net/guide/Performance_and_thread_safety.html">(链接)</a>,指出多个Unmarshal器的实例化可能是一个昂贵的操作。即使没有进行性能分析,我也可以告诉你,我的应用程序使用Unmarshal器池运行得更快。 - Bruno Chauvet
1
创建JXAB反编组器并不轻松,无论意图如何。 - Hector

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接