【协议转换和消息路由】camel-spring-boot-starter 实践

Apache Camel uses URIs to work directly with any kind of Transport or messaging model such as HTTP, ActiveMQ, JMS, JBI, SCA, MINA or CXF, as well as pluggable Components and Data Format options. Apache Camel is a small library with minimal dependencies for easy embedding in any Java application. Apache Camel lets you work with the same API regardless which kind of Transport is used - so learn the API once and you can interact with all the Components provided out-of-box.

以上是引用 Apache Camel 官网对它的定义。

Apache Camel 在编排模式中依托 URI 描述规则,实现了传输协议和消息格式的转换,即它具备协议转换,消息路由的能力。

白话翻译下Apache Camel功能:apache camel 能把业务数据封装在 Message 协议中,在各种不同的协议(如:HTTP,JMS,CXF等)中exchange下去。

接下来列举一个业务场景:

    定时抓取百度页面内容,并存储到本地磁盘。

    分析:1)百度提供的服务是http://www.baidu.com --> 这里的协议便是 http。

            2)抓取百度的内容 --> 这里的内容就是数据,camel抓取到数据会把它封装进 Message,

            3)抓取到的内容存储到本地磁盘 --> 本地磁盘的协议是 file, 存储下来涉及到内容的转移,即Message 的 Exchange.

简单代码实现:

package com.simonton.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.Test;

public class CamelDemoTest {

	@Test
	public void demo() throws Exception {
		//Camel 的上下文对象 类似Spring ApplicationContext
		CamelContext context = new DefaultCamelContext();
		// 添加路由
		context.addRoutes(new RouteBuilder() {
			@Override
			public void configure() throws Exception {
				from("timer://foo?fixedRate=true&delay=0&period=10000")
				.to("http4:www.baidu.com?bridgeEndpoint=true")
				.to("file:/Users/simonton/tmp/baidu?fileName=baidu.html");
			}
		});
		//启动
		context.start();
		while(true) {
			
		}
	}
}

上面这段代码,涉及到 Camel 的三个基础概念:CamelContext, RouteBuilder 和 EndPoint。

CamelContext: 相对好理解每个框架会定义自己的上下文。

RouteBuilder: 通过继承它可以实现一个路由规则,实现多个,可以通过调用顺序来编排路由规则业务。

EndPoint:  Camel是一个系统继承的基础服务组件,在已经编排好的路由规则中,EndPoint就是和其它系统进行通讯的设定点。这个“其它系统”,可以是本地或远程的文件系统,可以是进行业务处理的订单系统,可以是消息队列服务,可以是提供防伪地址的任何服务。Apache Camel 利用自身提供的组件(Component)支持广泛的通信协议,如 RPC,JMS,FTP,HTTP等。

        刚才简单demo了下每隔10秒抓取百度页面存储到本地磁盘,接下来,我们用springboot把 camel 做成一个微服务,当然业务也再强化下。

强化后的业务:

        1)每天上午8点到10点,每隔30分钟抓取一次百度页面,存储在本地。

        2)支持手动触发该业务。

微服务实现如下:

1)用gradle 构建好springboot项目,目录如下:

├── build.gradle
├── settings.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── simonton
    │   │           └── camel
    │   │               ├── CamelDemoApp.java
    │   │               └── router
    │   │                   ├── BaseRoute.java
    │   │                   ├── baidu
    │   │                   │   └── DownloadRouter.java
    │   │                   ├── demo
    │   │                   │   └── HelloRouter.java
    │   │                   └── utils
    │   │                       └── ContentTypeUtils.java
    │   └── resources
    │       └── application.properties
    └── test
        └── java
            └── com
                └── simonton
                    └── camel
                        └── CamelDemoTest.java

2) apache camel springboot 集成相关的 jar 依赖如下:

buildscript {
	repositories {
		jcenter()
	}
	
	dependencies {
		classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.6.RELEASE'
	}
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'

repositories {
    jcenter()
}

dependencies {
	compile 'org.springframework.boot:spring-boot-starter-web'
	compile group: 'org.apache.camel', name: 'camel-spring-boot-starter', version: '2.21.0'
	compile group: 'org.apache.camel', name: 'camel-http4-starter', version: '2.21.0'
	compile group: 'org.apache.camel', name: 'camel-servlet-starter', version: '2.21.0'
	compile group: 'org.apache.camel', name: 'camel-quartz2-starter', version: '2.21.0'
	compile 'org.springframework.boot:spring-boot-starter-test'
}

3) 主要业务代码download实现如下:

package com.simonton.camel.router.baidu;

import org.springframework.stereotype.Component;

import com.simonton.camel.router.BaseRoute;
import com.simonton.camel.router.utils.ContentTypeUtils;

@Component
public class DownloadRouter extends BaseRoute{

	@Override
	public void doConfigure() {
		//restful 手动触发url
		rest("/baidu")
		.produces(ContentTypeUtils.textPlain())
		.get("/download")
		.route()
		.to("direct:download");
		
		//定时任务触发
		from("quartz2:demo/download?cron=0 */30 8-10 * * ? *&job.name=download&stateful=true")
		.to("direct:download");
		
		//下载业务实现
		from("direct:download")
		.process(exchange -> {
			System.out.println(" download active...");
		})
		.to("http4:www.baidu.com?bridgeEndpoint=true&connectionClose=true")
		.to("file:/Users/simonton/tmp/baidu?fileName=baidu.html")
		.setBody(constant("download success..."))
		.end();
	}

}

4). 步骤3)中的 BaseRoute主要是在RouteBuilder基础上对异常做了下处理:

package com.simonton.camel.router;

import org.apache.camel.builder.RouteBuilder;

public abstract class BaseRoute extends RouteBuilder{

	@Override
	public void configure() throws Exception {
		handleException();
		doConfigure();
	}
	
	public abstract void doConfigure();
	
	public void handleException() {
		onException(Exception.class)
		.handled(true)
		.transform()
		.body()
		.setBody(constant("系统异常"))
		.end();
	}

}

5) 配置文件内容如下:

server.port=8888
camel.springboot.name=demo
camel.springboot.jmx-enabled=false
camel.component.quartz2.enabled=true
camel.component.quartz2.enable-jmx=false
#camel servlet 集成 context-path配置
camel.component.servlet.mapping.context-path=/demo/*

总结:

    Apache Camel 是一个系统继承的基础服务组件,具备消息转换和协议路由的能力,其拥有的各种现成的 component 使得 camel 可以轻松的支持 http,ftp,jms,amq等协议。Apache Camel可以轻松集成进 java  standard alone 程序,另外,通过 camel-servlet 可以轻松集成进 java web项目。利用Apache Camel具备的协议转换和消息路由的能力,可以轻松的实现文件转移服务,本人现已使用该框架落地了支付系统中支付通道对账文件的获取及转移服务。

完整源码:

github url: https://github.com/simonton/Camel.git

gitee url: https://gitee.com/simonton/camel.git

猜你喜欢

转载自my.oschina.net/simonton/blog/1673528