1

我正在关注spring 3.0.5HTTP 消息转换器,用于在控制器级别自动获取 java 对象。它适用于顺序请求。

但是当从服务器上的 REST 客户端发出并发请求时,java 对象出现不一致。我通过 REST 客户端发出相同类型的请求,但数据存在一些差异。

一些内部实例对象值变成了请求对象的空/空,甚至存在于 XML 中。(通过过滤器级别和控制器级别的日志验证)

注意一件事总是在对象的映射(键值对)中不一致。不知道这是什么原因。

我正在使用以下环境:

  1. 春天 3.0.5
  2. HTTP 消息转换器
  3. 雄猫 1.6
  4. jaxb 2.2

下面是xml的配置:

    <bean id="messageAdapter"
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="marshallingHttpMessageConverter" />
        </list>
    </property>
</bean>

    <bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
</bean>

控制器代码如下:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.sfnt.saas.provisioning.service.ProvisioningInterfaceManager;
import com.sfnt.saas.provisioning.util.messages.ContractData;
import com.sfnt.saas.provisioning.util.messages.ContractInfo;

@Controller
public class ProvisioningController {

    private final Log log = LogFactory.getLog(this.getClass());

    @Autowired
    private ProvisioningInterfaceManager provisioningInterfaceManager;

    @RequestMapping(value = {"/1.0/Contract"}, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public void deployContract(HttpServletRequest request,
            HttpServletResponse response, @RequestBody ContractData contractData)
            throws RuntimeException {

        ContractInfo contractInfo = null;
        contractInfo = provisioningInterfaceManager
                .deployContract(contractData);
        response.addHeader("Location", request.getRequestURL() + "/"
                + contractInfo.getContract().getContract());
    }
}

请帮忙 !!!

4

2 回答 2

0

我自己得到了这个问题的解决方案,我需要做的如下:

正如 spring 提供的 HttpMessageConverter 一样org.springframework.oxm.jaxb.Jaxb2Marshaller,在每个请求上创建 Marshaller/Unmarshaller 但不是JAXBContext全局创建的对象。

所以我需要做的 - 创建我自己的自定义 HttpMessageConverter 并创建 marshaller/unmarshaller 以及JAXBContext每个请求,在此之后我的问题消失了.. :) 下面是示例代码:

xml:

    <bean id="messageAdapter"
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="marshallingHttpMessageConverter" />
            </list>
        </property>
    </bean>

    <bean id="marshallingHttpMessageConverter"
        class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <property name="marshaller" ref="jaxbConvertor" />
        <property name="unmarshaller" ref="jaxbConvertor" />
    </bean>

    <bean id="jaxbConvertor" class="com.sfnt.saas.provisioning.web.JAXBConvertor">
        <property name="classesToBeBound">
            <list>
                      <value>com.project.yourclass1</value>
                      <value>com.project.yourclass2</value>
            </list>
        </property>
    </bean>

自定义转换器:

import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.UncategorizedMappingException;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

/**
 * This class will be responsible for providing auto conversion of
 * request/response body.
 * 
 * <h1>Note:</h1>
 * <p>
 * There is need to create custom converter as
 * <code>spring provided converter is
 * generating inconsistent data object in unmarshaling when concurrent request
 * came.</code>
 * <p>
 * In spring provided converter there is global JAXBContext is created and used
 * in all marshaling/unmarshaling that create object inconsistency when
 * concurrent request came.
 * 
 * @see Jaxb2Marshaller
 * @author Atul Kumar
 */
public class JAXBConvertor implements Marshaller, Unmarshaller {
    private Class<?>[] classesToBeBound;
    private final Log log = LogFactory.getLog(this.getClass());

    /**
     * This method will create JAXBContext in each request which is not done in
     * spring provided converter
     */
    @Override
    public Object unmarshal(Source source) throws IOException,
            XmlMappingException {
        try {
            javax.xml.bind.Unmarshaller jaxbUnmarshaller = JAXBContext
                    .newInstance(getClassesToBeBound()).createUnmarshaller();
            return jaxbUnmarshaller.unmarshal(source);
        } catch (JAXBException e) {
            log.error("Error in unmarshallering xml to object", e);
            throw new UncategorizedMappingException(e.getMessage(), e);
        }
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    /**
     * This method will create JAXBContext in each request which is not done in
     * spring provided converter
     */
    @Override
    public void marshal(Object graph, Result result) throws IOException,
            XmlMappingException {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(graph.getClass());
            javax.xml.bind.Marshaller jaxbMarshaller = jaxbContext
                    .createMarshaller();
            jaxbMarshaller.marshal(graph, result);
        } catch (JAXBException e) {
            log.error("Error in marshallering object to xml", e);
            throw new UncategorizedMappingException(e.getMessage(), e);
        }
    }

    /**
     * Set the list of Java classes to be recognized by a newly created
     * JAXBContext. Setting this property or {@link #setContextPath
     * "contextPath"} is required.
     */
    public synchronized void setClassesToBeBound(Class<?>... classesToBeBound) {
        this.classesToBeBound = classesToBeBound;
    }

    /**
     * Return the list of Java classes to be recognized by a newly created
     * JAXBContext.
     */
    public Class<?>[] getClassesToBeBound() {
        return this.classesToBeBound;
    }
}
于 2013-05-12T16:13:54.503 回答
0

它的妥协性能,请参阅下面的链接

http://javaeesupportpatterns.blogspot.in/2011/09/jaxbcontext-performance-problem-case.html

于 2013-09-12T13:28:05.227 回答