JMS 传输上的 REST 而不是 HTTP

REST on JMS Transport instead of HTTP

我正在尝试为 REST 创建多个通道,以便可以使用 http 协议从浏览器调用我的端点,或者其他应用程序可以通过将消息放入队列来异步调用。尽管我能够配置这两种传输类型。我能够访问 REST 服务,但在发送 JMS 消息时失败。

这是我用来重现问题的完整代码设置。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kp.swasthik</groupId>
    <artifactId>kp-rest-jms-artemis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>kp-rest-jms-artemis</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <cxf.version>3.1.10</cxf.version>
        <!-- <artemis.version>2.0.0</artemis.version> -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-jms</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-jms-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-artemis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

REST 服务

@Service
@Path("/kp")
public class KPRest {

    @Autowired
    private JmsTemplate jmsTemplate;

    @POST
    @Path("/hello")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(String hello){
        System.out.println(hello);
        return "Hello from CXF";
    }

    @GET
    @Path("/send-message")
    public String sendMessage(){
        jmsTemplate.send("cxf_queue", (session)->{
            TextMessage msg = session.createTextMessage();
            msg.setBooleanProperty("OnewayMessage", true);
            msg.setStringProperty("org.apache.cxf.message.Message.REQUEST_URI", "/kp/hello");
            msg.setText("JMS message");
            return msg;
        });
        return "Sent message";
    }

}

Cxf 配置

进口com.kp.swasthik.cxf.rest.KPRest;

@Configuration
public class CxfConfig {

    @Bean
    public Server jaxrsServerRest(Bus bus, KPRest rest){
        JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();
        server.setAddress("/kp");
        server.setBus(bus);
        server.setServiceBean(rest);
        server.setFeatures(Arrays.asList(new LoggingFeature()));
        return server.create();
    }

    @Bean
    public Server jaxrsServerJMS(Bus bus, KPRest rest, JMSConfigFeature feature){
        JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();
        server.setAddress("/");
        server.setTransportId("http://cxf.apache.org/transports/jms");
        server.setBus(bus);
        server.setServiceBean(rest);
        server.setFeatures(Arrays.asList(new LoggingFeature(), feature));
        return server.create();
    }

    @Bean
    public JMSConfigFeature getJMSFeature(JMSConfiguration jmsConfiguration) {
        JMSConfigFeature feature = new JMSConfigFeature();
        feature.setJmsConfig(jmsConfiguration);
        return feature;
    }

    @Bean
    public JMSConfiguration getjmsConfig(ConnectionFactory connectionFactory) {
        JMSConfiguration config = new JMSConfiguration();
        config.setConnectionFactory(connectionFactory);
        config.setTargetDestination("cxf_queue");
        return config;
    }
}

Spring 启动器 class

@SpringBootApplication
public class KpRestJmsArtimisApplication {

    public static void main(String[] args) {
        SpringApplication.run(KpRestJmsArtimisApplication.class, args);
    }
}

application.properties

spring.artemis.embedded.queues=cxf_queue
spring.artemis.embedded=true

我正在调用 send-message rest api,它将消息放置在 cxf_queue 中,它将被 CXF 端点读取。但是,由于 org.apache.cxf.message.Message.REQUEST_URI

中存在 .,我收到错误消息

这是堆栈跟踪。

javax.jms.JMSRuntimeException: AMQ129012: The property name 'org.apache.cxf.message.Message.REQUEST_URI' is not a valid java identifier.
    at org.apache.activemq.artemis.jms.client.ActiveMQMessage.checkProperty(ActiveMQMessage.java:919) ~[artemis-jms-client-1.3.0.jar:1.3.0]
    at org.apache.activemq.artemis.jms.client.ActiveMQMessage.setStringProperty(ActiveMQMessage.java:657) ~[artemis-jms-client-1.3.0.jar:1.3.0]
    at com.kp.swasthik.cxf.rest.KPRest.lambda[=15=](KPRest.java:37) ~[classes/:na]
    at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate.doInJms(JmsTemplate.java:574) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:484) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:570) ~[spring-jms-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at com.kp.swasthik.cxf.rest.KPRest.sendMessage(KPRest.java:34) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189) ~[cxf-rt-frontend-jaxrs-3.1.10.jar:3.1.10]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99) ~[cxf-rt-frontend-jaxrs-3.1.10.jar:3.1.10]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.run(ServiceInvokerInterceptor.java:59) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[cxf-core-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:262) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274) ~[cxf-rt-transports-http-3.1.10.jar:3.1.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_102]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_102]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_102]

不确定 Cxf 是否完全支持具有 JMS 传输类型的 REST。虽然在文档中它说它支持但我没有看到太多细节。并且也不确定是否有任何方法或 属性 来转义 . 字符。

我不知道你正在尝试做的事情的完整背景,但是这...

'org.apache.cxf.message.Message.REQUEST_URI' is not a valid java identifier.

...很清楚。你不能这样做...

msg.setStringProperty("org.apache.cxf.message.Message.REQUEST_URI", "/kp/hello");

...因为 JMS 属性中不能包含 . - 它们使用与 java 标识符(例如变量)相同的规则。

您可以在发送端将 . 替换为 _,然后在接收端将它们换回;如果您需要这种格式。

CXF 实现目前不遵循 JMS 规范。我会注意修复此问题,同时保持与旧 CXF 客户端的兼容性。

https://issues.apache.org/jira/browse/CXF-7344