camel+cxf+osgi+java对外发布多返回值的webservice服务

7 篇文章 0 订阅

        前段时间接到新的任务,需要对一个很有年代感的集成系统做新版升级,这套老系统下游有一个小的推送系统通过一个相对独立的小程序定时访问老系统的webservice服务获取数据。由于年代久远,推送系统相关的东西已经没人维护,只能寄希望于新集成下的的ESB按照老的webservice提供一模一样的服务。

      新系统下的ESB基于camel、osgi、fuse,因此决定采用camel cxf对外提供webservice。

      camel-cxf 参考资料:https://camel.apache.org/components/latest/cxf-component.html

                                         http://people.apache.org/~dkulp/camel/cxf.html

      本次接口的主要jar

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-cxf</artifactId>
    <version>2.15.0</version>
    <optional>true</optional>
</dependency>

     第一步,camel.xml中的endpoint配置,address对应接口发布后的服务地址,serviceClass对应想要发布的接口实现,properties中的entry是针对返回值的xml的标签名做的改造,ns_1对应命名空间。

    <camel-cxf:cxfEndpoint id="testEndpoint"
                           address="http://127.0.0.1:8080/xxx/xxx"
                           serviceClass="com.webservice.impl.TestServiceImpl">
        <camel-cxf:properties>
            <entry key="soap.env.ns.map">
                <map>
                    <entry key="ns_1" value="http://www.test.com/com/xxx/xxx"/>
                    <entry key="soapenv" value="http://schemas.xmlsoap.org/soap/envelope/"/>
                    <entry key="xsi" value="http://www.w3.org/2001/XMLSchema-instance"/>
                </map>
            </entry>
            <entry key="disable.outputstream.optimization" value="true"/>
        </camel-cxf:properties>
    </camel-cxf:cxfEndpoint>

     第二步,创建TestService,示例对应三个返回值,写法与传统的webservice定义一致。

@WebService(targetNamespace = "http://www.test.com/com/xxx/xxx")
public interface TestService {
    /**
     * @param result 取值结果 0成功,1失败
     * @param errMsg 错误或警告信息
     * @param outData 返回数据
     */
    @WebMethod
    @ResponseWrapper(localName = "getTestOutMsg", targetNamespace = "http://www.test.com/com/xxx/xxx")
    void getTestData(@WebParam(name = "result", targetNamespace = "http://www.test.com/com/xxx/xxx", mode = WebParam.Mode.OUT) Holder<Integer> result,
                     @WebParam(name = "errMsg", targetNamespace = "http://www.test.com/com/xxx/xxx", mode = WebParam.Mode.OUT) Holder<String> errMsg,
                     @WebParam(name = "outData", targetNamespace = "http://www.test.com/com/xxx/xxx", mode = WebParam.Mode.OUT) Holder<String> outData
    );

}

     第三步,TestServiceImpl

@WebService(targetNamespace = "http://www.test.com/com/xxx/xxx")
@Singleton
@OsgiServiceProvider(classes = TestService.class)
public class TestServiceImpl implements TestService {
    @Override
    public void getTestData(Holder<Integer> result, Holder<String> errMsg, Holder<String> outData) {
        result.value = 0;
        outData.value = dataStr;
        errMsg.value = "";
    }
}

    第四步,创建路由,回到之前的camel.xml中创建路由。testProcess是自定义的数据处理器,可以方便debug接口或者修改返回值,非必需,可以省略。

 <bean id = "testRouter" class="com.route.TestRouter">
        <property name="testProcess" ref="testProcess"/>
 </bean>

    第五步,创建router,这里面引入的endpoint对应开头定义的cxfEndpoint 的id ,.process这一步可以省略。

public class TestRouter extends RouteBuilder {

    private TestProcess testProcess;
    @Override
    public void configure() throws Exception {
        from("cxf:bean:testEndpoint?loggingFeatureEnabled=true")
                .process(testProcess)
                .log("request: ${body}");
    }

    public TestProcess getTestProcess() {
        return testProcess;
    }

    public void setTestProcess(TestProcess testProcess) {
        this.testProcess = testProcess;
    }
}

    第六步,创建process,这里面在process里面newserviceImpl也是无奈之举,这一步有的人是把它放在router定义的时候,

.process(new TestProcess(new TestServiceImpl()))用这样的方式引入,但是我在实际应用时,这种方式没法通过 @Inject
 @OsgiService注解引入别的模块接口。因此暂定目前这种写法,受限于个人水平,没有找到代替的方法。


@Singleton
public class TestProcess implements Processor {
    private Object instance = null;
    private Map<String, Method> operationMap = new ConcurrentHashMap<>();

    @Inject
    @OsgiService
    private TestOtherService testOtherService;

    private TestServiceImpl testService;

    @Override
    public void process(Exchange exchange) throws Exception {
        if(null == testService){
            testService = new TestServiceImpl();
        }
        instance = testService;
        initOperationMap(testService.getClass());
        String inputMessage = exchange.getIn().getBody(String.class);
        log.info("inputMessage : " + inputMessage);
        String operationName = exchange.getIn().getHeader(CxfConstants.OPERATION_NAME, String.class);
        Method method = operationMap.get(operationName);
        if (method == null) {
            throw new RuntimeException("找不到" + operationName + "对应的方法!");
        }
        try {
            Object body = exchange.getIn().getBody();
            if (body == null) {
                method.invoke(instance);
            } else {
                exchange.getIn().setBody(body);
                method.invoke(instance, exchange.getIn().getBody(Object[].class));
            }
        } catch (Exception e) {
            throw new RuntimeException("方法调用异常", e);
        }
    }

    private void initOperationMap(Class<?> beanClass) {
        WebService webService = beanClass.getDeclaredAnnotation(WebService.class);
        if (webService != null && !org.apache.cxf.common.util.StringUtils.isEmpty(webService.endpointInterface())) {
            try {
                Class serviceClass = Class.forName(webService.endpointInterface());
                processServiceClass(serviceClass);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        } else {
            processServiceClass(beanClass);
        }
    }
    private void processServiceClass(Class serviceClass) {
        for (Method method : serviceClass.getDeclaredMethods()) {
            String operationName = method.getName();
            WebMethod webMethod = method.getAnnotation(WebMethod.class);
            if (webMethod != null && !org.apache.cxf.common.util.StringUtils.isEmpty(webMethod.operationName())) {
                operationName = webMethod.operationName();
            }
            log.info("operationName: {} - method: {}", operationName, method);
            operationMap.put(operationName, method);
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值