如何在主线程中保持 apache camel 上下文活动
How to keep apache camel context alive in thread main
我正在尝试制作一个简单的应用程序,它将侦听来自 artemis 的一个队列,然后处理消息,然后在第二个队列中创建新消息。
我已经在方法 Main Camel 上下文中创建并添加了路由(它将消息转发到 bean)。为了测试这个路由以及这个 bean 是否正常工作,我发送了
此队列中的消息很少 - 在主线程中启动上下文之后
public static void main(String args[]) throws Exception {
CamelContext context = new DefaultCamelContext();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616", "admin", "admin");
context.addComponent("cmp/q2", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
context.addRoutes(new RouteBuilder() {
public void configure() {
from("cmp/q2:cmp/q2").bean(DataRequestor.class, "doSmth(${body}, ${headers})");
}
});
ProducerTemplate template = context.createProducerTemplate();
context.start();
for (int i = 0; i < 2; i++) {
HashMap<String, Object> headers = new HashMap<String, Object>();
headers.put("header1", "some header info");
template.sendBodyAndHeaders("cmp/q2:cmp/q2", "Test Message: " + i, headers);
}
context.stop();
}
在这种情况下,应用程序工作正常,但它会在方法 main 完成时停止 - 它只处理由它自己创建的消息。
现在,在我有了用于路由的测试 bean 之后,我想修改应用程序,使其启动并保持活动状态(保持 camle 上下文和例程活动)- 这样我就可以在 web UI 中手动创建按摩(活跃的 mq 管理控制台)。
但是我真的不知道怎么办。
我已经尝试使用 Thread.sleep(5000) 进行无限循环;
我试图在 main 方法中再启动一个线程(也有无限循环)。
但它没有用。(在无限循环的情况下,对我来说最可疑的是应用程序是 运行,但是当我在网络中创建消息时 UI 它只是消失了 - 并且系统中没有任何痕迹知道它是由我的 bean 在路由中处理的,假设它应该由我的 bean 处理,或者只是原封不动地留在队列中,但它只是消失了)。
现在我的问题是空的,但我已经浪费了 3 天的时间来寻找解决方案,所以任何建议或 link 教程或一些有价值的信息都将受到赞赏。
PS:我有一个痛苦的限制 - Spring 框架是不允许的。
至少你需要一个主线程来启动一个线程到 运行 骆驼路线,然后检查该线程何时完成。简单的 java 线程方法使用主循环来检查 .wait() 和骆驼路由线程的结束以在它完成(或关闭)时发出信号 .notify() 将完成工作。
从那里您可以查看执行程序服务或使用像 Apache Karaf 这样的微容器
PS。支持 Spring-免费!
我认为 运行 独立 camel 最简单的解决方案是用 camel Main. Camel online documentation has also an example of using it http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html 启动它。
为了以防万一,我将在此处复制粘贴示例代码:
public class MainExample {
private Main main;
public static void main(String[] args) throws Exception {
MainExample example = new MainExample();
example.boot();
}
public void boot() throws Exception {
// create a Main instance
main = new Main();
// bind MyBean into the registry
main.bind("foo", new MyBean());
// add routes
main.addRouteBuilder(new MyRouteBuilder());
// add event listener
main.addMainListener(new Events());
// set the properties from a file
main.setPropertyPlaceholderLocations("example.properties");
// run until you terminate the JVM
System.out.println("Starting Camel. Use ctrl + c to terminate the JVM.\n");
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {
from("timer:foo?delay={{millisecs}}")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Invoked timer at " + new Date());
}
})
.bean("foo");
}
}
public static class MyBean {
public void callMe() {
System.out.println("MyBean.callMe method has been called");
}
}
public static class Events extends MainListenerSupport {
@Override
public void afterStart(MainSupport main) {
System.out.println("MainExample with Camel is now started!");
}
@Override
public void beforeStop(MainSupport main) {
System.out.println("MainExample with Camel is now being stopped!");
}
}
}
路由会一直执行,直到您按下 Ctlr+c 或以其他方式停止...
如果您对此进行测试,请注意您的类路径中需要 example.properties 文件,其中包含 属性 millisecs
.
免责声明: 这是用 Kotlin 编写的,但移植到 java
有点微不足道
免责声明:这是为 Apache-Camel 2.24.2 编写的
免责声明:我也在学习 Apache-Camel。文档对我来说有点重
我尝试了 Main
路线来设置它,但很快就有点费解了。我知道这是一个 java 线程,但我使用的是 kotlin ATM,我将保留大部分类型和导入可用,以便 java 开发人员更容易。
class 听众
我首先要解决的问题是理解 Main
的生命周期。事实证明,您可以实现一个接口来添加此类事件的实现。通过这样的实现,我可以连接任何必须确保 camel
已经启动的例程(不需要猜测)。
import org.apache.camel.CamelContext
import org.apache.camel.main.MainListener
import org.apache.camel.main.MainSupport
typealias Action = () -> Unit
class Listener : MainListener {
private var afterStart: Action? = null
fun registerOnStart(action:Action) {
afterStart = action
}
override fun configure(context: CamelContext) {}
override fun afterStop(main: MainSupport?) {}
override fun afterStart(main: MainSupport?) {
println("started!")
afterStarted?.invoke().also { println("Launched the registered function") }
?: println("Nothing registered to start")
}
override fun beforeStop(main: MainSupport?) {}
override fun beforeStart(main: MainSupport?) {}
}
class ApplicationCore
然后我设置 context
的配置(Routes,Components,等等,...)
import org.apache.camel.CamelContext
import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.impl.SimpleRegistry
import org.apache.camel.main.Main
class ApplicationCore : Runnable {
private val main = Main()
private val registry = SimpleRegistry()
private val context = DefaultCamelContext(registry)
private val listener = Listener() // defined above
// for Java devs: this is more or less a constructor block
init {
main.camelContexts.clear()
listener.registerOnStart({ whateverYouAreDoing().start() })// <- your stuff should run in its own thread because main will be blocked
main.camelContexts.add(context)
main.duration = -1
context.addComponent("artemis", ...)// <- you need to implement your own
context.addRoutes(...)// <- you already know how to do this
...// <- anything else you could need to initialize
main.addMainListener(listener)
}
fun run() {
/* ... add whatever else you need ... */
// The next line blocks the thread until you close it
main.run()
}
fun whateverYouAreDoing(): Thread {
return Thread() {
ProducerTemplate template = context.createProducerTemplate();
for (i in 0..1) {
val headers = HashMap<String, Any>()
headers["header1"] = "some header info"
template.sendBodyAndHeaders("cmp/q2:cmp/q2", "Test Message: $i", headers)
}
context.stop()// <- this is not good practice here but its what you seem to want
}
}
}
在kotlin中,初始化相当容易。您可以轻松地将其翻译成 java 因为它非常简单
// top level declaration
fun main(vararg args:List<String>) = { ApplicationCore().run() }
我正在尝试制作一个简单的应用程序,它将侦听来自 artemis 的一个队列,然后处理消息,然后在第二个队列中创建新消息。
我已经在方法 Main Camel 上下文中创建并添加了路由(它将消息转发到 bean)。为了测试这个路由以及这个 bean 是否正常工作,我发送了 此队列中的消息很少 - 在主线程中启动上下文之后
public static void main(String args[]) throws Exception {
CamelContext context = new DefaultCamelContext();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616", "admin", "admin");
context.addComponent("cmp/q2", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
context.addRoutes(new RouteBuilder() {
public void configure() {
from("cmp/q2:cmp/q2").bean(DataRequestor.class, "doSmth(${body}, ${headers})");
}
});
ProducerTemplate template = context.createProducerTemplate();
context.start();
for (int i = 0; i < 2; i++) {
HashMap<String, Object> headers = new HashMap<String, Object>();
headers.put("header1", "some header info");
template.sendBodyAndHeaders("cmp/q2:cmp/q2", "Test Message: " + i, headers);
}
context.stop();
}
在这种情况下,应用程序工作正常,但它会在方法 main 完成时停止 - 它只处理由它自己创建的消息。 现在,在我有了用于路由的测试 bean 之后,我想修改应用程序,使其启动并保持活动状态(保持 camle 上下文和例程活动)- 这样我就可以在 web UI 中手动创建按摩(活跃的 mq 管理控制台)。
但是我真的不知道怎么办。 我已经尝试使用 Thread.sleep(5000) 进行无限循环; 我试图在 main 方法中再启动一个线程(也有无限循环)。 但它没有用。(在无限循环的情况下,对我来说最可疑的是应用程序是 运行,但是当我在网络中创建消息时 UI 它只是消失了 - 并且系统中没有任何痕迹知道它是由我的 bean 在路由中处理的,假设它应该由我的 bean 处理,或者只是原封不动地留在队列中,但它只是消失了)。
现在我的问题是空的,但我已经浪费了 3 天的时间来寻找解决方案,所以任何建议或 link 教程或一些有价值的信息都将受到赞赏。
PS:我有一个痛苦的限制 - Spring 框架是不允许的。
至少你需要一个主线程来启动一个线程到 运行 骆驼路线,然后检查该线程何时完成。简单的 java 线程方法使用主循环来检查 .wait() 和骆驼路由线程的结束以在它完成(或关闭)时发出信号 .notify() 将完成工作。
从那里您可以查看执行程序服务或使用像 Apache Karaf 这样的微容器
PS。支持 Spring-免费!
我认为 运行 独立 camel 最简单的解决方案是用 camel Main. Camel online documentation has also an example of using it http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html 启动它。 为了以防万一,我将在此处复制粘贴示例代码:
public class MainExample {
private Main main;
public static void main(String[] args) throws Exception {
MainExample example = new MainExample();
example.boot();
}
public void boot() throws Exception {
// create a Main instance
main = new Main();
// bind MyBean into the registry
main.bind("foo", new MyBean());
// add routes
main.addRouteBuilder(new MyRouteBuilder());
// add event listener
main.addMainListener(new Events());
// set the properties from a file
main.setPropertyPlaceholderLocations("example.properties");
// run until you terminate the JVM
System.out.println("Starting Camel. Use ctrl + c to terminate the JVM.\n");
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {
from("timer:foo?delay={{millisecs}}")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Invoked timer at " + new Date());
}
})
.bean("foo");
}
}
public static class MyBean {
public void callMe() {
System.out.println("MyBean.callMe method has been called");
}
}
public static class Events extends MainListenerSupport {
@Override
public void afterStart(MainSupport main) {
System.out.println("MainExample with Camel is now started!");
}
@Override
public void beforeStop(MainSupport main) {
System.out.println("MainExample with Camel is now being stopped!");
}
}
}
路由会一直执行,直到您按下 Ctlr+c 或以其他方式停止...
如果您对此进行测试,请注意您的类路径中需要 example.properties 文件,其中包含 属性 millisecs
.
免责声明: 这是用 Kotlin 编写的,但移植到 java
有点微不足道免责声明:这是为 Apache-Camel 2.24.2 编写的
免责声明:我也在学习 Apache-Camel。文档对我来说有点重
我尝试了 Main
路线来设置它,但很快就有点费解了。我知道这是一个 java 线程,但我使用的是 kotlin ATM,我将保留大部分类型和导入可用,以便 java 开发人员更容易。
class 听众
我首先要解决的问题是理解 Main
的生命周期。事实证明,您可以实现一个接口来添加此类事件的实现。通过这样的实现,我可以连接任何必须确保 camel
已经启动的例程(不需要猜测)。
import org.apache.camel.CamelContext
import org.apache.camel.main.MainListener
import org.apache.camel.main.MainSupport
typealias Action = () -> Unit
class Listener : MainListener {
private var afterStart: Action? = null
fun registerOnStart(action:Action) {
afterStart = action
}
override fun configure(context: CamelContext) {}
override fun afterStop(main: MainSupport?) {}
override fun afterStart(main: MainSupport?) {
println("started!")
afterStarted?.invoke().also { println("Launched the registered function") }
?: println("Nothing registered to start")
}
override fun beforeStop(main: MainSupport?) {}
override fun beforeStart(main: MainSupport?) {}
}
class ApplicationCore
然后我设置 context
的配置(Routes,Components,等等,...)
import org.apache.camel.CamelContext
import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.impl.SimpleRegistry
import org.apache.camel.main.Main
class ApplicationCore : Runnable {
private val main = Main()
private val registry = SimpleRegistry()
private val context = DefaultCamelContext(registry)
private val listener = Listener() // defined above
// for Java devs: this is more or less a constructor block
init {
main.camelContexts.clear()
listener.registerOnStart({ whateverYouAreDoing().start() })// <- your stuff should run in its own thread because main will be blocked
main.camelContexts.add(context)
main.duration = -1
context.addComponent("artemis", ...)// <- you need to implement your own
context.addRoutes(...)// <- you already know how to do this
...// <- anything else you could need to initialize
main.addMainListener(listener)
}
fun run() {
/* ... add whatever else you need ... */
// The next line blocks the thread until you close it
main.run()
}
fun whateverYouAreDoing(): Thread {
return Thread() {
ProducerTemplate template = context.createProducerTemplate();
for (i in 0..1) {
val headers = HashMap<String, Any>()
headers["header1"] = "some header info"
template.sendBodyAndHeaders("cmp/q2:cmp/q2", "Test Message: $i", headers)
}
context.stop()// <- this is not good practice here but its what you seem to want
}
}
}
在kotlin中,初始化相当容易。您可以轻松地将其翻译成 java 因为它非常简单
// top level declaration
fun main(vararg args:List<String>) = { ApplicationCore().run() }