簡體   English   中英

如何在線程主線程中保持 apache 駱駝上下文

[英]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?) {}
}

類 ApplicationCore

然后我設置了context的配置( RoutesComponents等,...)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM