本篇文章对应的完整项目源码地址:
15-ApacheCamel-CXF-Demo-Server(Code First)
_16-ApacheCamel-CXF-Demo-Client
"15-ApacheCamel-CXF-Demo-Server(Code First)" 是参照官方Demo例子写的:https://github.com/apache/camel/tree/master/examples/camel-example-cxf
"16-ApacheCamel-CXF-Demo" 是根据日常最简原则写的Demo。
Apache Camel 相关所有Demo代码,已上传GitHub,需要的请自取:GitHub - Apache Camel 完整Demo
如果觉得还不错,请点star
前言
首先假定,你是使用过Apache CXF 或者 WebService的,如不了解,请先移步 WebService(Apache CXF)分享。
如果你之前看过Apache Camel 集成 CXF的前两篇:
Apache Camel - 14 - CXF组件、Apache Camel - 15 - CXF组件(2)
你会发现,其中的Demo样例,都是基于WSDL文件来发布WebService的。
因为在此之前,没有在官方Demo中找到,也有可能是我看走眼了没有发现(心塞...)。
言归正传,下面看下基于代码优先方式发布WebService
Apache Camel 集成 Apache CXF 发布WebService,基于代码优先的方式
这里先介绍下WebService(CXF)服务端发布的两种方式:基于WSDL方式 和 纯代码方式
- 基于WSDL方式:这种方式一般情况是第三方给你一个WSDL文档,然后你根据这个WSDL文档生成服务端代码,JDK原生的我并没有试过,我之前用的都是CXF的命令方式生成的服务端代码,然后在开发业务代码,启动服务端,发布WebService
- 纯代码方式:这种方式是最原始的方式,也是字面意思,只要你写过WebService,就一定能理解,参考:WebService(3)_开发流程(原生/JDK自带工具)
Apache Camel 集成 CXF 也是可以用以上两种方式来发布WebService,可惜之前我只找到基于WSDL的,可能是我英文不好,错过了。
下面看下关键代码:
pom.xml
<!--apache camel-->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>2.22.0</version>
</dependency>
<!--apache cxf-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.2.5</version>
</dependency>
<!--logback-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!--apache commons-->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
发布的接口,就像开发普通WebService一样,添加@WebService以及@WebMethod注解
package com.server.service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* @author CYX
* @create 2018-12-27-19:59
*/
@WebService
public interface BaseicQuery {
/**
* 查询人员信息
*
* @param queryCondition 基础查询
* @return
*/
@WebMethod
String queryPeopleInfo(@WebParam(name = "queryCondition") String queryCondition);
}
发布接口的实现类
package com.server.service.impl;
import com.server.service.BaseicQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author CYX
* @create 2018-12-27-20:00
*/
public class BaseicQueryImpl implements BaseicQuery {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseicQueryImpl.class);
@Override
public String queryPeopleInfo(String queryCondition) {
LOGGER.info("queryCondition : " + queryCondition);
return "copy that";
}
}
路由的process处理类:
package com.server.process;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.cxf.common.message.CxfConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
/**
* @author CYX
* @create 2018-12-27-20:36
*/
public class BaseicQueryProcess implements Processor {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseicQueryProcess.class);
private Class<?> beanClass;
private Object instance;
public BaseicQueryProcess(Object object) {
beanClass = object.getClass();
instance = object;
}
@Override
public void process(Exchange exchange) throws Exception {
String inputMessage = exchange.getIn().getBody(String.class);
LOGGER.info("inputMessage : " + inputMessage);
String operationName = exchange.getIn().getHeader(CxfConstants.OPERATION_NAME, String.class);
Method method = findMethod(operationName, exchange.getIn().getBody(Object[].class));
Object response = method.invoke(instance, exchange.getIn().getBody(Object[].class));
exchange.getOut().setBody(response);
}
private Method findMethod(String operationName, Object[] parameters) throws SecurityException, NoSuchMethodException {
return beanClass.getMethod(operationName, getParameterTypes(parameters));
}
private Class<?>[] getParameterTypes(Object[] parameters) {
if (parameters == null) {
return new Class[0];
}
Class<?>[] answer = new Class[parameters.length];
int i = 0;
for (Object object : parameters) {
answer[i] = object.getClass();
i++;
}
return answer;
}
}
这个类是关键,它通过反射来调用接口实现类中的方法,仔细看。
路由类:
package com.server.route;
import com.server.App;
import com.server.process.BaseicQueryProcess;
import com.server.service.impl.BaseicQueryImpl;
import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author CYX
* @create 2018-12-27-20:05
*/
public class BaseQueryRoute extends RouteBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseQueryRoute.class);
@Override
public void configure() throws Exception {
from(App.BASEQUERY_SERVICE_URL_ADDRESS).process(new BaseicQueryProcess(new BaseicQueryImpl()));
}
}
将接口实现类传到process 构造函数中。
主类:
package com.server;
import com.server.conf.LogBackConfigLoader;
import com.server.route.BaseQueryRoute;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Apache Camel With CXF-JAXRS(Code First)
* <p>
* Apache Camel集成Apache CXF-JAXRS,发布WebService(代码优先)
*
* @author CYX
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
private static final String LOGBACK_FILENAME = "./conf/logback.xml";
public static final String BASEICQUERY_SERVICE_URL = "http://localhost:9999/baseQueryService";
public static final String BASEQUERY_SERVICE_URL_ADDRESS = "cxf://" + BASEICQUERY_SERVICE_URL + "?serviceClass=com.server.service.BaseicQuery";
public static void main(String[] args) {
try {
LogBackConfigLoader.loadLogBack(LOGBACK_FILENAME);
CamelContext camelContext = new DefaultCamelContext();
camelContext.start();
camelContext.addRoutes(new BaseQueryRoute());
LOGGER.info("baseic query service address : " + BASEICQUERY_SERVICE_URL + "?wsdl");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
}
主类 启动类 没啥好解释的吧。
以上Demo中,最关键的是process处理类,没有这层调用关系,就没法调用到接口实现类,这个需要注意。
看下Demo启动测试,启动服务端:
看下WSDL文档:
然后我们用标准流程生成 Client 客户端代码,调用测试一下:
/**
* Hello world!
*/
public class ClientApp {
public static void main(String[] args) {
BaseicQueryService baseicQueryService = new BaseicQueryService();
BaseicQuery baseicQuery = baseicQueryService.getBaseicQueryPort();
String resultMessage = baseicQuery.queryPeopleInfo("server , do you copy");
System.out.println(resultMessage);
}
}
服务端日志:
客户端接收日志: