1.添加依賴包
gradle依賴:
compile 'org.apache.camel:camel-spring:2.20.3'
2.添加Spring配置信息
spring-camel.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext xmlns="http://camel.apache.org/schema/spring">
<packageScan>
<package>com.chz.apps.esb.camel.routes</package>
<excludes>**.*Excluded*</excludes>
<includes>**.*</includes>
</packageScan>
</camelContext>
</beans>
com.chz.apps.esb.camel.routes包是用於存放camel的路由類
3.編寫路由類(錯誤的類)
此處使用本地文件往ftp自動上傳文件爲例:
package com.chz.apps.esb.camel.routes;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
/**
* 本地文件往服務器自動同步機制
*/
@Component
public class FileTransFtpRouteBuilder extends RouteBuilder {
@Override
public void configure() {
from("file:D:\\tmp\\camel")
.to("ftp:ftpUsername:[email protected]");
}
}
4.問題描述
上面的builder是參考《Apache Camel Developer's Cookbook》第23頁實例編寫。每次啓動的時候,會發現創建的route並沒有添加到Camel的CamelContext中,也就是說路由並沒有生效。
經過源碼分析,Apache Camel在於Spring進行集成的時候,使用CamelContextFactoryBean進行相關Bean實例的統一管理。而使用packageScan進行啓動時,需要調用如下方法:
@Override
protected void findRouteBuildersByPackageScan(String[] packages, PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
// add filter to class resolver which then will filter
getContext().getPackageScanClassResolver().addFilter(filter);
PackageScanRouteBuilderFinder finder = new PackageScanRouteBuilderFinder(getContext(), packages, getContextClassLoaderOnStart(),
getBeanPostProcessor(), getContext().getPackageScanClassResolver());
finder.appendBuilders(builders);
// and remove the filter
getContext().getPackageScanClassResolver().removeFilter(filter);
}
finder.appendBuilders(builders);此方法用於掃描包路徑下面所有類,如果不是Spring的bean,則使用路由初始化方法,加載到Camel容器中。而書中提到使用Component註解後,會導致此處自動過濾掉:
在dubug的時候,日誌如下:
[MI TCP Connection(3)-127.0.0.1] efaultPackageScanClassResolver DEBUG Searching for implementations of org.apache.camel.RoutesBuilder in packages: [com.chz.apps.esb.camel.routes]
[MI TCP Connection(3)-127.0.0.1] efaultPackageScanClassResolver DEBUG Found: [class com.chz.apps.esb.camel.routes.FileTransFtpRouteBuilder]
[MI TCP Connection(3)-127.0.0.1] DefaultListableBeanFactory DEBUG Returning cached instance of singleton bean 'fileTransFtpRouteBuilder'
[MI TCP Connection(3)-127.0.0.1] PackageScanRouteBuilderFinder DEBUG Ignoring RouteBuilder class: class com.chz.apps.esb.camel.routes.FileTransFtpRouteBuilder
通過分析源碼(PackageScanRouteBuilderFinder.shouldIgnoreBean方法),只要是Spring已經加載的bean,此處不會做任何處理。所以正確的方式應該是去掉Component註解。
/**
* Appends all the {@link org.apache.camel.builder.RouteBuilder} instances that can be found on the classpath
*/
public void appendBuilders(List<RoutesBuilder> list) throws IllegalAccessException, InstantiationException {
Set<Class<?>> classes = resolver.findImplementations(RoutesBuilder.class, packages);
for (Class<?> aClass : classes) {
LOG.trace("Found RouteBuilder class: {}", aClass);
// certain beans should be ignored
if (shouldIgnoreBean(aClass)) {
LOG.debug("Ignoring RouteBuilder class: {}", aClass);
continue;
}
if (!isValidClass(aClass)) {
LOG.debug("Ignoring invalid RouteBuilder class: {}", aClass);
continue;
}
// type is valid so create and instantiate the builder
@SuppressWarnings("unchecked")
RoutesBuilder builder = instantiateBuilder((Class<? extends RoutesBuilder>) aClass);
if (beanPostProcessor != null) {
// Inject the annotated resource
beanPostProcessor.postProcessBeforeInitialization(builder, builder.toString());
}
LOG.debug("Adding instantiated RouteBuilder: {}", builder);
list.add(builder);
}
}
protected boolean shouldIgnoreBean(Class<?> type) {
Map<String, ?> beans = applicationContext.getBeansOfType(type, true, true);
if (beans == null || beans.isEmpty()) {
return false;
}
return true;
}
5.編寫路由類(正確的類)
package com.chz.apps.esb.camel.routes;
import org.apache.camel.builder.RouteBuilder;
/**
* 本地文件往服務器自動同步機制
*/
public class FileTransFtpRouteBuilder extends RouteBuilder {
@Override
public void configure() {
from("file:D:\\tmp\\camel")
.to("ftp:ftpUsername:[email protected]");
}
}