46、Camel部署与路由:从JBoss到OSGi及注解路由的实践

Camel部署与路由:从JBoss到OSGi及注解路由的实践

1. Camel在JBoss AS中的部署

在启动JBoss AS后,控制台会输出启动信息,如:

15:16:43,882 INFO [ServerImpl] JBoss (Microcontainer) [5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221053)] Started in 27s:452ms

之后,将WAR文件复制到指定目录:

cp target/riderautoparts-war-jboss-1.0.war ~/jboss/server/default/deploy

可以通过查看JBoss控制台来了解部署进度。例如,Camel会报告它已获取JBoss类加载器:

15:18:42,636 INFO [STDOUT] 2010-05-30 15:18:42,636 [main] INFO CamelContextFactoryBean - Using custom PackageScanClassResolver: org.apache.camel.jboss.JBossPackageScanClassResolver@75d8af

JBoss AS使用嵌入式的Apache Tomcat作为Servlet容器,应用的Web服务可通过以下URL访问:

http://localhost:8080/riderautoparts-war-jboss-1.0/services/inventory?wsdl

以下是在JBoss应用服务器中部署Camel的优缺点:
| 优点 | 缺点 |
| — | — |
| 利用JBoss AS容器 | 需要特殊的Camel JBoss组件来解决类加载问题 |
| 应用可利用Java EE应用服务器提供的功能 | |
| JBoss AS容器管理Camel的生命周期 | |
| 受益于应用服务器的管理和监控功能 | |
| 提供熟悉的运行时平台 | |

2. Camel与OSGi

OSGi是Java平台的分层模块系统,提供完整的动态组件模型,支持热部署。Apache Camel的所有JAR文件都符合OSGi规范,可在OSGi容器中部署。下面以Apache Karaf OSGi运行时为例,介绍如何准备和部署Rider Auto Parts应用。

2.1 设置Maven生成OSGi包

pom.xml 文件中,将 packaging 元素设置为 bundle

<packaging>bundle</packaging>

使用Apache Felix Maven Bundle插件生成JAR文件中的 MANIFEST.MF 条目,在 pom.xml <build> 部分添加以下配置:

<build>
  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>2.1.0</version>
    <extensions>true</extensions>
    <configuration>
      <instructions>
        <Bundle-Name>${project.artifactId}</Bundle-Name>
        <Bundle-SymbolicName>riderautoparts-osgi</Bundle-SymbolicName>
        <Export-Package>
            camelinaction,
            camelinaction.inventory
        </Export-Package>
        <Import-Package>*</Import-Package>
        <DynamicImport-Package>*</DynamicImport-Package>
        <Implementation-Title>Rider Auto Parts OSGi</Implementation-Title>
        <Implementation-Version>${project.version}</Implementation-Version>
      </instructions>
    </configuration>
  </plugin> 
</build>

该插件可设置要导入和导出的包,这里设置导出 camelinaction camelinaction.inventory 两个包。运行 mvn package 目标,可在 target/classes/META-INF 目录中看到生成的 MANIFEST.MF 条目。

2.2 安装和运行Apache Karaf

http://karaf.apache.org 下载并安装最新版本的Apache Karaf(编写时为Apache Karaf 2.1.2),安装只需解压zip文件。
启动Karaf:
- Unix系统: bin/karaf
- Windows系统: bin/karaf.bat

在安装Rider Auto Parts应用之前,需要安装Camel和Apache CXF。通过以下命令添加Camel特性描述:

features:addUrl mvn:org.apache.camel.karaf/apache-camel/2.5.0/xml/features

由于Apache Karaf 2.1版本在使用Apache CXF时存在问题,需要下载一个文件并保存到 etc 目录,命名为 custom.properties

curl http://svn.apache.org/repos/asf/servicemix/smx4/features/trunk/assembly/src/main/filtered-resources/etc/jre.properties > etc/custom.properties

该问题将在2.2版本中修复。
使用以下命令查看可用特性:

features:list

安装示例应用所需的特性:

features:install http
features:install camel
features:install camel-cxf
2.3 部署示例应用

Karaf可从多种源安装OSGi包,如文件系统或本地Maven仓库。使用Maven安装时,先将应用安装到本地Maven仓库:

mvn install

然后在Karaf shell中使用以下命令部署应用:

osgi:install mvn:com.camelinaction/riderautoparts-osgi/1.0

安装后,Karaf会输出分配给安装包的Bundle ID,例如:

Bundle ID: 98

使用 osgi:list 命令查看应用安装情况:

[98] [Installed] [] [] [60] riderautoparts-osgi (1.0.0)

应用默认未启动,使用以下命令启动:

osgi:start 98

再次使用 osgi:list 命令查看应用状态:

[98] [Installed] [] [Started] [60] riderautoparts-osgi (1.0.0)

可以使用 log:display 命令查看日志,确认Apache Camel已启动:

15:46:32,396 | INFO  | ExtenderThread-6 | DefaultCamelContext | e.camel.impl.DefaultCamelContext 1025 | Apache Camel 2.5.0 (CamelContext: myCamelContext) started

使用SoapUI发送测试请求,WSDL文件可通过以下URL访问:

http://localhost:9000/inventory?wsdl

测试完成后,使用以下命令停止OSGi容器:

osgi:shutdown

以下是在OSGi容器中部署Camel的优缺点:
| 优点 | 缺点 |
| — | — |
| 利用OSGi实现模块化 | 涉及OSGi的学习曲线 |
| 提供类加载器隔离和热部署 | 许多第三方框架不支持OSGi |
| 开源社区和大厂商支持OSGi | 需要额外努力确定模块的包导入和导出 |

3. 使用注解进行消息路由

Camel提供基于注解的路由功能,允许使用普通Java bean进行路由,无需编写DSL代码。以下以Rider Auto Parts的库存更新为例进行说明。

3.1 Rider Auto Parts的库存更新场景

Rider Auto Parts的供应商定期发送库存更新信息,通过JMS的 partnerInventoryUpdate 队列进入系统,更新 inventoryDB 数据库。假设有一个 InventoryUpdater 类可将库存更新信息写入数据库:

import javax.sql.DataSource; 
import org.springframework.jdbc.core.JdbcTemplate;

public class InventoryUpdater {
    private JdbcTemplate jdbc;
    public InventoryUpdater(DataSource ds) {
        jdbc = new JdbcTemplate(ds);
    }
    public void updateInventory(Inventory inventory) {
        jdbc.execute(toSql(inventory));                 
    }    
    private String toSql(Inventory inventory) {
        Object[] args = new Object[] {
            inventory.getSupplierId(), inventory.getPartId(), 
            inventory.getName(), inventory.getAmount()};
        return String.format("insert into partner_inventory " + 
            "(supplier_id, part_id, name, amount) values " + 
            "('%s', '%s', '%s', '%s')", args);
    } 
}
3.2 使用 @Consume 接收消息

使用 @Consume 注解将 partnerInventoryUpdate 队列直接连接到 updateInventory 方法:

import javax.sql.DataSource;
import org.apache.camel.Consume; 
import org.springframework.jdbc.core.JdbcTemplate;

public class InventoryUpdater {
    ...    
    @Consume(uri = "jms:partnerInventoryUpdate")       
    public void updateInventory(Inventory inventory) {
        jdbc.execute(toSql(inventory));
    } 
...    
}

添加该注解后,Camel会从 partnerInventoryUpdate 队列消费消息,并调用 updateInventory 方法。 @Consume 注解接受任何Camel端点URI。
运行以下Maven命令测试示例:

mvn clean test

测试用例会向 partnerInventoryUpdate 队列发送消息,并检查更新是否写入数据库。

3.3 加载注解类到Camel

使用这些注解需要设置必要的依赖: camel-core camel-spring ,并使用 SpringCamelContext 作为基础应用。在Spring XML文件中创建 SpringCamelContext

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring" />

这会在Spring应用上下文中注册 CamelBeanPostProcessor ,该处理器会检查新注册的bean是否有 @Consume @Produce 注解,并将bean连接到指定的Camel端点。
在Spring XML文件中创建bean:

<bean class="camelinaction.InventoryUpdater"/>  
3.4 引用共享端点

如果多个bean从相同的端点URI消费消息,可以定义一个端点并从每个bean引用它。在上下文设置Camel端点:

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
  <endpoint id="inventoryQueue" uri="jms:partnerInventoryUpdate"/> 
</camelContext>

@Consume 注解中引用该端点:

@Consume(ref = "inventoryQueue") 
public void updateInventory(Inventory inventory) {
    jdbc.execute(toSql(inventory)); 
}
3.5 指定使用的CamelContext

如果在一个Spring XML文件中定义了两个 CamelContext 元素,需要确保 @Consume 注解指定应用的 CamelContext ,避免为每个 CamelContext 创建新的消费者。

4. 总结与最佳实践
  • 确保可靠关闭 :花时间配置和测试应用,确保在计划维护、升级或出现意外问题时能可靠关闭,避免对业务产生负面影响。
  • 使用现有运行时环境 :Camel灵活可嵌入现有生产环境,无需为使用Camel引入新的生产环境,应尽早在项目中测试应用能否在现有环境中部署和运行。

Camel部署与路由:从JBoss到OSGi及注解路由的实践

5. 隐藏Camel API的意义与挑战

在某些场景下,我们希望限制对Camel的依赖,这就需要隐藏Camel API。隐藏这些API不仅能降低系统对Camel的依赖程度,还能为解决集成问题提供新的思路。然而,这也带来了一些挑战,比如如何在不使用Camel DSL的情况下实现消息路由和处理。接下来,我们将深入探讨如何利用Camel的注解和相关技术来实现这一目标。

6. 注解路由的进阶应用
6.1 @Produce 注解的使用

前面提到了 @Consume 注解用于接收消息,而 @Produce 注解则用于向Camel端点发送消息。例如,我们有一个需要发送库存更新请求的场景,以下是一个简单的示例:

import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;

public class InventoryRequestSender {
    @Produce(uri = "jms:partnerInventoryRequest")
    private ProducerTemplate producerTemplate;

    public void sendInventoryRequest(InventoryRequest request) {
        producerTemplate.sendBody(request);
    }
}

在这个示例中, @Produce 注解将 producerTemplate jms:partnerInventoryRequest 端点关联起来,通过调用 sendBody 方法,我们可以将 InventoryRequest 对象发送到指定端点。

6.2 结合 @Consume @Produce 实现消息流转

我们可以将 @Consume @Produce 注解结合使用,实现消息的完整流转。例如,当接收到供应商的库存更新消息后,经过处理再发送一个确认消息给供应商:

import javax.sql.DataSource;
import org.apache.camel.Consume;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.springframework.jdbc.core.JdbcTemplate;

public class InventoryProcessor {
    private JdbcTemplate jdbc;

    @Produce(uri = "jms:partnerInventoryConfirmation")
    private ProducerTemplate producerTemplate;

    public InventoryProcessor(DataSource ds) {
        jdbc = new JdbcTemplate(ds);
    }

    @Consume(uri = "jms:partnerInventoryUpdate")
    public void processInventoryUpdate(Inventory inventory) {
        jdbc.execute(toSql(inventory));
        InventoryConfirmation confirmation = new InventoryConfirmation(inventory.getSupplierId());
        producerTemplate.sendBody(confirmation);
    }

    private String toSql(Inventory inventory) {
        Object[] args = new Object[] {
            inventory.getSupplierId(), inventory.getPartId(), 
            inventory.getName(), inventory.getAmount()};
        return String.format("insert into partner_inventory " + 
            "(supplier_id, part_id, name, amount) values " + 
            "('%s', '%s', '%s', '%s')", args);
    }
}

在这个示例中, InventoryProcessor 类使用 @Consume 注解接收库存更新消息,处理后使用 @Produce 注解发送确认消息。

7. 隐藏中间件的实现思路

隐藏中间件可以让用户只看到业务接口,将远程传输和Camel API的复杂性隐藏在干净的客户端API之后。以下是实现这一目标的一般步骤:
1. 定义业务接口 :明确系统的业务功能,定义相应的接口。例如,定义一个 InventoryService 接口:

public interface InventoryService {
    void updateInventory(Inventory inventory);
    Inventory getInventory(String supplierId, String partId);
}
  1. 实现业务接口 :在实现类中使用Camel的注解和组件来完成具体的业务逻辑。例如:
import org.apache.camel.Consume;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;

public class InventoryServiceImpl implements InventoryService {
    @Produce(uri = "jms:partnerInventoryUpdate")
    private ProducerTemplate updateProducer;

    @Consume(uri = "jms:partnerInventoryResponse")
    private ProducerTemplate responseConsumer;

    @Override
    public void updateInventory(Inventory inventory) {
        updateProducer.sendBody(inventory);
    }

    @Override
    public Inventory getInventory(String supplierId, String partId) {
        // 发送查询请求
        InventoryQuery query = new InventoryQuery(supplierId, partId);
        updateProducer.sendBody(query);
        // 接收响应
        return (Inventory) responseConsumer.receiveBody();
    }
}
  1. 提供客户端API :将业务接口暴露给客户端,客户端只需要调用接口方法,无需关心底层的Camel实现。
8. 总结与未来展望

通过上述的介绍,我们了解了Camel在不同环境下的部署方式,包括在JBoss AS和OSGi容器中的部署,以及如何使用注解进行消息路由和隐藏Camel API。以下是一些关键要点总结:
| 部署方式 | 优点 | 缺点 |
| — | — | — |
| JBoss AS | 利用容器功能、管理生命周期、提供熟悉平台 | 需要特殊组件解决类加载问题 |
| OSGi | 模块化、热部署、社区和厂商支持 | 学习曲线、第三方框架支持不足 |

在使用注解进行路由时, @Consume @Produce 注解为我们提供了简单而强大的消息处理能力,同时隐藏Camel API和中间件可以降低系统对Camel的依赖,提高系统的可维护性和扩展性。

未来,随着技术的不断发展,Camel可能会在更多的场景中得到应用,我们也可以进一步探索如何结合其他技术,如微服务架构、云计算等,来提升系统的性能和可靠性。同时,对于OSGi等技术,我们可以深入学习其原理和应用,充分发挥其模块化和动态性的优势。

总之,掌握Camel的部署和路由技术,能够为我们解决复杂的集成问题提供有力的支持,帮助我们构建更加高效、灵活的系统。

内容概要:本文提出了一种针对大规模电动汽车接入电网的双层优化调度策略,并基于IEEE33节点系统进行了建模仿真分析,配套提供了完整的Matlab代码实现。该策略构建了上层电网运行优化下层电动汽车充电调度的双层协同模型,综合考虑电网负荷削峰填谷、电压稳定性维持以及电动汽车用户充电需求满足等多重目标,采用先进的优化算法实现对电动汽车集群的智能有序调度。研究详细阐述了双层模型的构建逻辑、目标函数设计、约束条件设定及迭代求解流程,有效降低了电网峰谷差,提升了配电系统对可再生能源的消纳能力,兼具扎实的理论深度明确的工程应用前景。; 适合人群:电气工程、电力系统及其自动化、能源系统优化等相关专业的研究生、科研人员以及从事智能电网、电动汽车调度、分布式能源管理等领域工作的工程师和技术人员。; 使用场景及目标:①深入研究高比例电动汽车接入对配电网运行特性的影响机制;②掌握电力系统双层优化建模方法及其在实际系统中的求解技巧;③实现电动汽车集群的协同调度车网互动(V2G)优化控制;④作为撰写学术论文、开展课题研究或复现高水平期刊成果的技术参考代码基础。; 阅读建议:建议读者结合所提供的Matlab代码逐行理解双层优化模型的数学表达程序实现细节,重点剖析上下层模型之间的信息交互机制收敛判据,可通过调整电动汽车渗透率、充电行为参数或引入分布式电源等场景进行拓展性仿真,以深化对智能调度策略适应性的认识。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值