[英]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 上下文和 routin 活動)-以便我可以在 Web UI 中手動創建消息(活動 mq 管理控制台) )。
但我真的不知道怎么做。 我用 Thread.sleep(5000); 嘗試了無限循環; 我試圖在 main 方法中再啟動一個線程(也有無限循環)。 但它不起作用。(在無限循環的情況下,對我來說最可疑的是應用程序正在運行,但是當我在 Web UI 中創建消息時,它只是消失了 - 系統中沒有任何痕跡表明它是由我的 bean 處理的在路由中,假設它應該由我的 bean 處理或者只是保持在隊列中不變,但它只是消失了)。
我現在我的問題是愚蠢的,但我已經浪費了 3 天時間來尋找解決方案,因此感謝任何建議或教程鏈接或一些有價值的信息。
PS:我有一個痛苦的限制 - 不允許使用 Spring 框架。
至少您需要一個主線程來啟動一個線程來運行駱駝路線,然后檢查該線程何時完成。 使用主循環檢查 .wait() 的簡單 java 線程方法和駱駝路由線程的結尾在完成(或關閉)時向 .notify() 發出信號將完成工作。
從那里您可以查看執行程序服務或使用像 Apache Karaf 這樣的微容器
附注。 無彈簧的道具!
我認為運行獨立駱駝最簡單的解決方案是使用駱駝Main啟動它。 Camel 在線文檔也有一個使用它的例子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 開發人員更容易。
我首先要解決的是理解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?) {}
}
然后我設置了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() }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.