我正在关注 spring 3.0.5 的 HTTP消息转换器,以便自动获取控制器级别的java对象。它适用于顺序请求。
但是在服务器上提供来自REST客户端的并发请求时,java对象会出现不一致。我通过REST客户端提供相同类型的请求,但数据存在一些差异。
某些内部实例对象值为null /空请求对象甚至存在于XML中。 (通过过滤级别和控制器级别的日志验证)
请注意,对象的map(键值对)中始终存在一个不一致的事情。不知道有什么理由。
我正在使用以下环境:
以下是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());
}
}
请帮助!!!
答案 0 :(得分: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>
<强> CustomConveter:强>
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;
}
}
答案 1 :(得分:0)