简体   繁体   English

如何在线程主线程中保持 apache 骆驼上下文

[英]How to keep apache camel context alive in thread main

I'm trying to make simple application that will listen one queue from artemis and then proceed messages and after that create new message in second queue.我正在尝试制作一个简单的应用程序,它将侦听来自 artemis 的一个队列,然后处理消息,然后在第二个队列中创建新消息。

I have created in method Main Camel context and added routing (it forwards messages to bean).我在方法 Main Camel 上下文中创建并添加了路由(它将消息转发到 bean)。 And to test this routing and that this bean works correctly I'm sending few messages to this queue - rigth after context started in main thread为了测试这个路由并且这个 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();
}

And in this case application works fine, but it stops when method main completed - it proceess only messages that were created by it self.在这种情况下,应用程序工作正常,但在方法 main 完成时它会停止 - 它只处理由它自己创建的消息。 Now after I have test bean that is used in routing, I want to modify application such way that it should start and stay active(keeping camle context and routin alive ) - so that i can create massages manually in web UI (active mq management console).现在,在我拥有用于​​路由的测试 bean 之后,我想修改应用程序,使其应该启动并保持活动状态(保持 camle 上下文和 routin 活动)-以便我可以在 Web UI 中手动创建消息(活动 mq 管理控制台) )。

But I really don't know how.但我真的不知道怎么做。 I have tried infinite loop with Thread.sleep(5000);我用 Thread.sleep(5000); 尝试了无限循环; I tried to start one more thread(also with infinite loop) in main method.我试图在 main 方法中再启动一个线程(也有无限循环)。 But it didn't work.(The most suspicious for me in case with infinite loop is that apllication is running, but when i create message in web UI it just desapears - and no any traces in system out that it was processed by my bean in routing, a suppose that it should be processed by my bean or just stay in the queue untouched, but it just disapears).但它不起作用。(在无限循环的情况下,对我来说最可疑的是应用程序正在运行,但是当我在 Web UI 中创建消息时,它只是消失了 - 系统中没有任何痕迹表明它是由我的 bean 处理的在路由中,假设它应该由我的 bean 处理或者只是保持在队列中不变,但它只是消失了)。

I now that my question is dummy, but I already have wasted 3 days to find a solution, so any advices or link to tutorials or some valueable information are appreciated.我现在我的问题是愚蠢的,但我已经浪费了 3 天时间来寻找解决方案,因此感谢任何建议或教程链接或一些有价值的信息。

PS: I've got one painfull restriction - Spring frameworks are not allowed. PS:我有一个痛苦的限制 - 不允许使用 Spring 框架。

At the very minimum you need a main thread to kick off a thread to run the camel route and then check for when that thread is done.至少您需要一个主线程来启动一个线程来运行骆驼路线,然后检查该线程何时完成。 The simple java threading approach using the main loop to check .wait() and the end of the camel route thread to signal .notify() when it finishes (or shutdown) would get the job done.使用主循环检查 .wait() 的简单 java 线程方法和骆驼路由线程的结尾在完成(或关闭)时向 .notify() 发出信号将完成工作。

From there you can look into an executor service or use a micro-container like Apache Karaf从那里您可以查看执行程序服务或使用像 Apache Karaf 这样的微容器

PS.附注。 Props for going Spring-free!无弹簧的道具!

I think the most simple solution for running standalone camel is starting it with camel Main .我认为运行独立骆驼最简单的解决方案是使用骆驼Main启动它。 Camel online documentation has also an example of using it http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html . Camel 在线文档也有一个使用它的例子http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html I will copy paste the example code here just in case:我将在这里复制粘贴示例代码以防万一:

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!");
        }
    }
}

The route keeps executing until you hit Ctlr+c or stop it in some other way... If you test this, notice that you need example.properties file in your classpath, with the property millisecs .路由一直执行,直到您按下 Ctlr+c 或以其他方式停止它...如果您对此进行测试,请注意您的类路径中需要 example.properties 文件,其属性millisecs

Disclaimer: this is written in Kotlin but it is somewhat trivial to port to java免责声明:这是用 Kotlin 编写的,但移植到 Java 有点微不足道

Disclaimer: this is written for Apache-Camel 2.24.2免责声明:这是为 Apache-Camel 2.24.2 编写的

Disclaimer: I am also learning about Apache-Camel.免责声明:我也在学习 Apache-Camel。 The docs are a little heavy for me文档对我来说有点沉重

I tried the Main route to set it up but it quickly got a little convoluted.我尝试了Main路线来设置它,但很快就变得有点复杂。 I know that this is a java thread but I'm using kotlin ATM, I'll leave most of the types and imports available so it's easier for java devs.我知道这是一个 java 线程,但我使用的是 kotlin ATM,我将保留大部分类型和导入可用,以便 java 开发人员更容易。

class Listener类监听器

The first I had to fight with was understanding the lifecycle of Main .我首先要解决的是理解Main的生命周期。 It turns out that there is an interface you can implement to add in the implementations of such events.事实证明,您可以实现一个接口来添加此类事件的实现。 With such an implementation I can hook up any routines that have to be sure that camel has started (no guessing required).通过这样的实现,我可以连接任何必须确保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类 ApplicationCore

Then I set up the configuration of the context ( Routes , Components , etc,...)然后我设置了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
        }
    }
}

In kotlin , initialization is rather easy.kotlin 中,初始化相当容易。 You can easily translate this into java because it is quite straight forward您可以轻松地将其翻译成 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