如何在线程主线程中保持Apache骆驼上下文的生命

时间:2018-10-19 09:12:58

标签: java apache-camel activemq-artemis

我正在尝试制作一个简单的应用程序,该应用程序将监听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处理或不加改动地留在队列中,但它消失了。

我现在的问题是假的,但是我已经浪费了三天时间来寻找解决方案,因此,任何建议或指向教程的链接或一些有价值的信息都将受到赞赏。

PS:我有一个痛苦的限制-不允许使用Spring框架。

3 个答案:

答案 0 :(得分:0)

至少,您需要一个主线程来启动一个线程来运行骆驼路线,然后检查该线程何时完成。使用主循环检查.wait()并在完成(或关闭)时通知.notify()的骆驼路由线程结束的简单java线程化方法可以完成工作。

您可以从那里查看执行程序服务,或使用像Apache Karaf这样的微型容器

PS。无弹簧的道具!

答案 1 :(得分:0)

我认为运行独立骆驼的最简单解决方案是从骆驼Main开始。骆驼在线文档也提供了使用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或以其他方式将其停止... 如果对此进行测试,请注意,您需要在类路径中具有属性millisecs的example.properties文件。

答案 2 :(得分:0)

免责声明:这是用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的配置(路由组件等...)

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() }