1

コントローラーレベルでJavaオブジェクトを自動的に取得するために、Spring 3.0.5のHTTPメッセージコンバーターに従っています。シーケンシャルリクエストでは問題なく動作します。

しかし、サーバー上のRESTクライアントから同時リクエストを送信すると、Javaオブジェクトに矛盾が生じます.RESTクライアントを介してデータにいくつかの違いがある同じタイプのリクエストを送信しています.

一部の内部インスタンス オブジェクト値は、XML に存在する場合でも要求オブジェクトの null/空になりました。(フィルタ レベルおよびコントローラ レベルでのロギングにより検証済み)

オブジェクトのマップ (キーと値のペア) で常に矛盾が生じることに注意してください。この理由はわかりません。

以下の環境を使用しています。

  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

その妥協のパフォーマンス、以下のリンクを参照してください

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

于 2013-09-12T13:28:05.227 に答える
0

自分でこの問題の解決策を見つけました。私がする必要があるのは以下のとおりです。

Spring がHttpMessageConverter を提供org.springframework.oxm.jaxb.Jaxb2Marshallerし、リクエストごとに Marshaller/Unmarshaller を作成しているため、JAXBContextグローバルに作成されたオブジェクトではありません。

だから私がしなければならないこと - 私自身のカスタム HttpMessageConverter を作成し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 に答える