{"id":16933910,"url":"https://github.com/mathieucarbou/pubsub","last_synced_at":"2026-04-02T17:25:59.193Z","repository":{"id":9760868,"uuid":"11728225","full_name":"mathieucarbou/pubsub","owner":"mathieucarbou","description":"EventBus system for publish and subscribe to events within an application","archived":false,"fork":false,"pushed_at":"2023-11-06T15:30:53.000Z","size":201,"stargazers_count":33,"open_issues_count":1,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-14T01:09:56.555Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://oss.carbou.me/pubsub/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mathieucarbou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-07-29T00:51:08.000Z","updated_at":"2024-01-18T14:15:16.000Z","dependencies_parsed_at":"2024-10-13T21:01:52.373Z","dependency_job_id":null,"html_url":"https://github.com/mathieucarbou/pubsub","commit_stats":null,"previous_names":["mycila/pubsub"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mathieucarbou/pubsub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathieucarbou%2Fpubsub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathieucarbou%2Fpubsub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathieucarbou%2Fpubsub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathieucarbou%2Fpubsub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mathieucarbou","download_url":"https://codeload.github.com/mathieucarbou/pubsub/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathieucarbou%2Fpubsub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311443,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T20:50:46.963Z","updated_at":"2026-04-02T17:25:59.174Z","avatar_url":"https://github.com/mathieucarbou.png","language":"Java","funding_links":[],"categories":["进程间通信"],"sub_categories":["Spring Cloud框架"],"readme":"**Table of Contents**\n\n- [Mycila PubSub](#mycila-pubsub)\n\t- [Maven Repository](#maven-repository)\n\t- [Documentation](#documentation)\n\t\t- [Sample](#sample)\n\t\t- [Usage](#usage)\n\t\t\t- [Subscribing](#subscribing)\n\t\t\t- [Publishing](#publishing)\n\t\t\t- [Synchronous requests](#synchronous-requests)\n\t\t\t- [Asynchronous requests](#asynchronous-requests)\n\t\t\t- [Request answers](#request-answers)\n\t\t- [Features](#features)\n\t\t\t- [Topics and Event types](#topics-and-event-types)\n\t\t\t- [In-Memory event system](#in-memory-event-system)\n\t\t\t- [Memory management](#memory-management)\n\t\t\t- [Exception handling](#exception-handling)\n\t\t\t- [Topic Matchers](#topic-matchers)\n\t\t\t- [Annotation support](#annotation-support)\n\t\t\t\t- [Subscribers](#subscribers)\n\t\t\t\t- [Publisher](#publisher)\n\t\t\t\t- [Requests](#requests)\n\t\t\t\t- [Answering requests](#answering-requests)\n\t\t\t- [Event dispatching strategies](#event-dispatching-strategies)\n\t\t\t\t- [Synchronous Safe Dispatching](#synchronous-safe-dispatching)\n\t\t\t\t- [Synchronous Unsafe Dispatching](#synchronous-unsafe-dispatching)\n\t\t\t\t- [Asynchronous Safe Dispatching](#asynchronous-safe-dispatching)\n\t\t\t\t- [Asynchronous Unsafe Dispatching](#asynchronous-unsafe-dispatching)\n\t\t\t\t- [Broadcast Ordered Dispatching](#broadcast-ordered-dispatching)\n\t\t\t\t- [Broadcast Unordered Dispatching](#broadcast-unordered-dispatching)\n\t\t\t\t- [Custom strategy](#custom-strategy)\n\t\t\t- [Integration](#integration)\n\t\t\t\t- [Google Guice](#google-guice)\n\n# Mycila PubSub #\n\nMycila Event is a new powerful event framework for in-memory event management. It has a lot of features similar to [EventBus](https://eventbus.dev.java.net/) but is better written and uses Java Concurrency features to provide you with:\n\n * Asynchronous event dispatching\n * Multicasting events\n * Topic matchers: enable a subscriber (and a vetoers) to subscribe to many topics\n * Annotation support: you can annotate your methods to decouple your code from Mycila Event and subscribe, publish and veto\n * Memory management through hard and weak references\n\n__Project Status:__\n\n - __OSGI Compliant:__ \u003cimg width=\"100px\" src=\"http://www.sonatype.com/system/images/W1siZiIsIjIwMTMvMDQvMTIvMTEvNDAvMzcvMTgzL05leHVzX0ZlYXR1cmVfTWF0cml4X29zZ2lfbG9nby5wbmciXV0/Nexus-Feature-Matrix-osgi-logo.png\" title=\"OSGI Compliant\"\u003e\u003c/img\u003e\n - __Build Status:__ [![Build Status](https://travis-ci.org/mycila/pubsub.png?branch=master)](https://travis-ci.org/mycila/pubsub)\n - __Issues:__ https://github.com/mathieucarbou/pubsub/issues\n\n## Maven Repository ##\n\n__Releases__\n\nAvailable in Maven Central Repository: http://repo1.maven.org/maven2/com/mycila/pubsub/\n\n__Snapshots__\n \nAvailable in OSS Repository:  https://oss.sonatype.org/content/repositories/snapshots/com/mycila/pubsub/\n\n__Maven dependency__\n\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.mycila\u003c/groupId\u003e\n        \u003cartifactId\u003emycila-pubsub\u003c/artifactId\u003e\n        \u003cversion\u003eX.Y.ga\u003c/version\u003e\n    \u003c/dependency\u003e\n\n__Maven sites__\n\n - [5.0.ga](http://mycila.github.io/pubsub/reports/5.0.ga/index.html)\n\n## Documentation ##\n\nMycila Event is a new powerful event framework for in-memory event management. It has a lot of features similar to [EventBus](https://eventbus.dev.java.net/) but is better designed, uses Java Concurrency features and has a lot of more event features than EventBus, which are really useful when you work with a complex system driven by event messaging.\n\n### Sample ###\n\n    import static com.mycila.event.api.topic.Topics.*;\n    \n    // first create an event service\n    Dispatcher dispatcher = Dispatchers.synchronousSafe(ErrorHandlers.rethrowErrorsAfterPublish());\n    \n    // then subscribe\n    TopicMatcher matcher = only(\"app/events/swing/button\").or(topics(\"app/events/swing/fields/**\"));\n    dispatcher.subscribe(matcher, String.class, new Subscriber\u003cString\u003e() {\n        public void onEvent(Event\u003cString\u003e event) throws Exception {\n            System.out.println(\"Received: \" + event.source());\n        }\n    });\n    \n    // and publish\n    dispatcher.publish(topic(\"app/events/swing/button\"), \"Hello !\");\n\nWhen you subscribe, you need to give to which topic to subscribe and for which event type.\n\n### Usage ###\n\n#### Subscribing ####\n\nSubscribing is done with the Dispatcher.subscribe method, which take the topic to subscribe to, the event type and an instance of `Subscriber\u003cT\u003e`, where T is the event type. The method receives an Event object, containing the timestamp (in nanoseconds) and the source.\n\n__Example:__\n\n    dispatcher.subscribe(only(\"prog/events/a\").or(matching(\"prog/events/b/**\")), String.class, new Subscriber\u003cString\u003e() {\n        public void onEvent(Event\u003cString\u003e event) throws Exception {\n            sequence.add(event.getSource());\n        }\n    });\n\n#### Publishing ####\n\nPublishing is done by simply sending to a topic an event object.\n\n    dispatcher.publish(topic(\"prog/events/a\"), \"Hello for a\");\n\n#### Synchronous requests ####\n\nAn event system is asynchronous by default, but you sometimes need to wait for an answer before proceeding. This is the request/response pattern that everyone know. You can create a request and wait for its response (or wait with a timeout). The request is created through `Messages.createRequest`, where you can pass request parameters. The you call `MessageRequest.getResponse()` to obtain the response.\n\n    MessageRequest\u003cInteger\u003e adddRequest = Messages.createRequest(new int[]{1, 2, 3, 4, 5}, \"param2\");\n    dispatcher.publish(topic(\"system/add\"), adddRequest);\n    int sum = adddRequest.getResponse(1, TimeUnit.SECOND);\n\n#### Asynchronous requests ####\n\nYou can also request in asynchronous mode by adding listeners, which will be triggered when the response will be received;\n\n    MessageRequest\u003cInteger\u003e adddRequest = Messages.createRequest(new int[]{1, 2, 3, 4, 5}, \"param2\");\n    adddRequest.addListener(new MessageListener\u003cInteger\u003e() {\n        public void onResponse(Integer value) {\n            assertEquals(15, value.intValue());\n        }\n    \n        public void onError(Throwable t) {\n            t.printStackTrace();\n            fail();\n        }\n    });\n    dispatcher.publish(topic(\"system/add\"), adddRequest);\n\n#### Request answers ####\n\nTo be able to respond to an answer on a topic, you simply have to subscribe, with the specific event type `MessageResponse`:\n\n    dispatcher.subscribe(only(\"system/add\"), MessageResponse.class, new Subscriber\u003cMessageResponse\u003cInteger\u003e\u003e() {\n        public void onEvent(Event\u003cMessageResponse\u003cInteger\u003e\u003e event) throws Exception {\n            int[] p = (int[]) event.getSource().getParameters()[0];\n            System.out.printl(event.getSource().getParameters()[1]); // output the second parameter\n            int c = 0;\n            for (int i : p) c += i;\n            event.getSource.reply(c);\n        }\n    });\n\nThe event type is a special class which enable to take the parameters and reply a response. You could also respond by an exception if an error occured in the subscriber:\n\n    event.getSource().replyError(new ArithmeticException(\"Overflow !\"));\n\n### Features ###\n\n#### Topics and Event types ####\n\nWhen you subscribe, you subscribe in a Topic for a given event type. Event type subclasses are allowed to be received by a subscriber accepting its super-class. In example, if you subscribe to `Topic.topic(\"buttons/ok\")` with event type `ActionListener.class`, you can publish any implementation of `ActionListener` and it will be received by subscribers accepting the type (and sub-types) `ActionListener`.\n\n#### In-Memory event system ####\n\nMycila Event is not a JMS solution ! Like EventBus, Mycila Event resolves intra-process communication. In example, it can be used in a Swing GUI or in a complex modular framework to handle communication between plugins.\n\nThus, __Mycila Event must be fast, thread-safe and scalable.__\n\n#### Memory management ####\n\nLike EventBus, Mycila Event supports *hard and weak subscriptions*. A hard subscription will always remain and must be unregistered if not needed anymore. A weak subscription will be automatically removed when the subscriber is no longer in use.\n\nBy default, if nothing is specified, Mycila Event uses a hard reference. this is very useful when you simply bind a listener like this:\n\n    dispatcher.subscribe(matcher, String.class, new Subscriber\u003cString\u003e() {\n        public void onEvent(Event\u003cString\u003e event) throws Exception {\n            System.out.println(\"Received: \" + event.source());\n        }\n    });\n\nReachability control can be done by annotating the class with `@Reference`. In example, suppose you have a plugin class subscribing for events. You can annotate the class like this:\n\n    @Reference(Reachability.WEAK)\n    public class MyPlugin implements Subscriber\u003cString\u003e {\n        public void onEvent(Event\u003cString\u003e event) throws Exception {\n            System.out.println(\"Received: \" + event.source());\n        }\n        public void start() {\n            // start the plugin\n        }\n    }\n    \n    MyPlugin pluginLoadedByAnotherSystem = ...;\n    dispatcher.subscribe(matcher, String.class, pluginLoadedByAnotherSystem);\n\nWhen registering the plugin, a weak registration will be done so that if the plugin is unloaded or not used anymore, the subscription could be removed automatically.\n\n`@Reference` can also be put on methods, when used with annotations.\n\n#### Exception handling ####\n\nBy default, if a subscriber launches an exception, the exception is rethrown immediately, in the thread firering the event. You can change this behavior by providing your own `ErrorHandler`, or by using existing one:\n\n - `ErrorHandlers.ignoreErrors()`: ignore all exceptions thrown by subscribers\n - `ErrorHandlers.rethrow()`: the default behavior.\n\nTo create an Dispatcher with the appropriate event handler, you just have to set the `ErrorHandler` instance when creating it:\n\n    Dispatcher dispatcher = Dispatchers.synchronousSafe(ErrorHandlers.ignoreErrors());\n\n#### Topic Matchers ####\n\nWhen you register a subscriber, you need to pass the type of event you want to receive and a matcher to math topics you want to listen to. TopicMatcher can be created with the `Topics` class. You can compose matchers.\n\n * `Topics.only(exactName)`: matches a single topic name. *Example:* `Topics.only(\"app/events/buttons/ok\")`\n * `Topics.topics(pattern)`: matches several topic by using an Ant expression. *Example:* `Topics.topics(\"app/events/buttons/**\")`\n * `Topics.any()`: matches any topic\n * `Topics.not(matcher)`: invert the given matcher\n * `matcher.and(matcher)`: any matcher can be composed with another matcher with an *and*. In this case, all matchers must match given topic event for the subscriber to receive it. This is quite an uncommon case.\n * `matcher.or(matcher)`: any matcher can be composed with another matcher with an *or*. In this case, the subscriber will receive events matching the two matchers. This is a common case where you would like to receive in one subscriber the same events from different topics.\n\nIn example, to set a catch-all subscriber, you could do:\n\n    dispatcher.subscribe(Topics.any(), Object.class, new Subscriber\u003cObject\u003e() {\n        public void onEvent(Event\u003cObject\u003e event) throws Exception {\n            System.out.println(\"Received: \" + event.source());\n        }\n    });\n\n#### Annotation support ####\n\nMycila Event provides annotations to create publishers and subscribers decoupled from the Dispatcher service.\n\n##### Subscribers #####\n\nYou can annotate any method in your class to receive events with the `@Subscribe` annotation. It takes in arguments the list of topics (an Ant expression matching topics) to listen to and the type of event.\n\nThese annotations must be placed on methods having one parameter: `Event` for listening to events.\n\nYou can use the `@Reference` annotation to control if the listeners is weak or not. This annotation can be place on the method, or, if you have in your class several annotated methods to listen for events, you can place the `@Reference` annotation in the class directly.\n\n___By default, a subscription has a HARD reference. So be VERY CAREFUL when you register listeners implemented by your classes to make them WEAK if they have a shorter lifecycle than the Dispatcher.___\n\n__Subscribe to events__\n\n    class MyClass1 {\n        @Subscribe(topics = \"prog/events/a/**\", eventType = String.class)\n        private void handle(Event\u003cString\u003e event) {\n            // do something\n        }\n    }\n\nIn your code, after having created a `Dispatcher`, you can use the `AnnotationProcessors` to register annotated methods like this:\n\n    MyClass1 c1 = new ...\n    \n    AnnotationProcessor processor = AnnotationProcessors.create(dispatcher);\n    processor.process(c1);;\n\n##### Publisher #####\n\nPublishers can be created using the annotation `@Publish`. You can completely decouple your code by creating interface (or abstract classes) that will be automatically generated thanks to annotations.\n\nIn example:\n\n    private static interface B {\n        @Publish(topics = \"prog/events/a\")\n        void send(String a, int b);\n    }\n    \n    static abstract class C {\n        @Publish(topics = {\"prog/events/a/a1\", \"prog/events/a/allA\"})\n        abstract void send(String a, int b);\n    }\n\nThese two classes defines publishing methods. B will publish two events (a string and an integer) to one topic, and C will publish two events in two topics.\n\nTo automatically generate their implementation, you can use, after having created a Dispacther:\n\n    B b = annotationProcessor.proxy(B.class);\n    C c = annotationProcessor.proxy(C.class);\n    \n    b.send(\"Hello for a\", 1);\n    c.send(\"Hello for a1\", 4);\n\nB and C are classes in your code that you can use directly to publish events.\n\nYou can annotate a generated Publisher method by `@Multiple`. If the publishing method is given an array or collection of objects, each object will be published independently as an event.\n\nIn example:\n\n    abstract class MyCustomPublisher2 {\n        @Publish(topics = \"a/topic/path\")\n        @Multiple\n        abstract void send(int event1, String... otherEvents);\n    }\n    [...]\n    myCustomPublisher2.send(1, \"each\", \"string\", \"will\", \"be\", \"an\", \"event\")\n\n__Note__: you can then create abstract classes which act sa event managers: abstract methods annotated by @Publish will be generated and concrete methods annotated by @Subscribe will receive events.\n\n##### Requests #####\n\nRequesting methods acts the same as publishers. They differ in the annotation, which provides a way to timeout and wait for the response to come back. In example, suppose you have an additioner plugin exposing its computation method to the topic `system/add`. You can create a subscriber like this:\n\n    interface Requestor {\n        @Request(topic = \"system/add\", timeout = 1, unit = TimeUnit.SECONDS)\n        int addNumbers(int... p);\n    }\n    Dispatcher dispatcher = Dispatchers.synchronousSafe();\n    AnnotationProcessor processor = AnnotationProcessors.create(dispatcher);\n    Requestor req = processor.proxy(Requestor.class);\n    assertEquals(15, req.addNumbers(1,2,3,4,5));\n\nGiven the nature of a method call, it is obvious that the call is synchronous and will wait either indefinitely for a response or only with the given time.\n\n##### Answering requests #####\n\nThere is two way for answering requests: as we seen, we have to register a simple subscriber. It can be done like this:\n\n    static class DU {\n        @Subscribe(topics = \"system/du\", eventType = MessageResponse.class)\n        void duRequest(Event\u003cMessageResponse\u003cInteger\u003e\u003e event) {\n            String folder = (String) event.getSource().getParameters()[0];\n            System.out.println(\"du request on folder \" + folder);\n            // call du -h \u003cfolder\u003e\n            if (\"notFound\".equals(folder))\n                event.getSource().replyError(new FileNotFoundException(\"du did not found folder \" + folder));\n            else\n                event.getSource().reply(40);\n        }\n    }\n    Dispatcher dispatcher = Dispatchers.synchronousSafe();\n    AnnotationProcessor processor = AnnotationProcessors.create(dispatcher);\n    DU du = new DU();\n    processor.process(du);\n\nHopefully, there is a better way. The request sends as parameter a String, and the subscriber replies with an integer. So what if we can simply call a method ? This can be done like this:\n\n    static class DU {\n        @Answers(topics = \"system/du\")\n        int getSize(String folder) throws FileNotFoundException {\n            System.out.println(\"du request on folder \" + folder);\n            // call du -h \u003cfolder\u003e\n            if (\"notFound\".equals(folder))\n                throw new FileNotFoundException(\"du did not found folder \" + folder);\n            return 40;\n        }\n    }\n    Dispatcher dispatcher = Dispatchers.synchronousSafe();\n    AnnotationProcessor processor = AnnotationProcessors.create(dispatcher);\n    DU du = new DU();\n    processor.process(du);\n\nThe method output (or the exception) will then be used as the reply if an request is made to the topic `system/du`.\n\n#### Event dispatching strategies ####\n\nThere are several strategies regarding about how you want the order of events and the order of listeners be respected and whether or not you have multiple threads publishing events.\n\n##### Synchronous Safe Dispatching #####\n\n * Listeners are called in the order they subscribed\n * Events are published __one after one__\n * Only one thread can publish at a time\n\nThis strategy guarantees the order of listeners called and that only one thread will hit the listeners at a time. Thus, your listeners don't need to be thread-safe. The publish method thus block until the previous publishing is finished.\n\nThis behavior allows you to have stateful non thread-safe subscribers. When multiple threads are publishing, this strategy is slower.\n\n    Dispatcher dispatcher = Dispatchers.synchronousSafe();\n\n##### Synchronous Unsafe Dispatching #####\n\n * Listeners are called in the order they subscribed\n * Events are published immediately\n * Several threads can publish at a time\n\nThis strategy guarantees the order of listeners called. The publish method only block for the current thread, meaning that a thread can be publishing while another thread also starting publishing an event. Thus, your subscribers can be hit at the same time by two or more threads.\n\nYour subscribers need to be stateless and thread-safe. Multiple threads can publish at the same time.\n\n    Dispatcher dispatcher = Dispatchers.synchronousUnsafe();\n\n##### Asynchronous Safe Dispatching #####\n\n * Listeners are called in the order they subscribed\n * Events are published one after one\n * Many threads can enqueue an event at one time\n * One background thread is responsible to dequeue and fire events\n * A queue is used to enqueue events before they are processed.\n\nThis strategy guarantees the order of listeners called and the order of published events. The publish method *does not block* and the publisher thread immediately returns. The event is queued and wait for its turn to be processed by the background thread.\n\nThis strategy is useful when your publishers must execute as fast as possible, but be careful to also have fast subscribers to not fill the queue. This behavior allows you to have stateful non thread-safe subscribers since only one thread will dequeue and fire events.\n\nSince this strategy uses an unbounded queue, be careful to have fast subscribers and to not publish events more than your subscribers can consume.\n\n    Dispatcher dispatcher = Dispatchers.asynchronousSafe();\n\n##### Asynchronous Unsafe Dispatching #####\n\n * Listeners are called in the order they subscribed\n * Several events (so listeners) are processed at the same time\n * Many threads can publish an event at one time\n * Several background threads are responsible for firing events\n\nThis strategy guarantees the order of listeners called, but not the order of event. Basically, each call to publish will return immediately. All events in the queue are handled by a thread pool.\n\nThis strategy is useful when your publishers must execute as fast as possible, and event publishing needs to be processed quickly, but by respecting listener order. This dispatcher can be seen as a concurrent event dispatcher, respecting listener order.\n\nSince this strategy uses an unbounded queue, be careful to have fast subscribers and to not publish events more than your subscribers can consume.\n\nYour subscribers need to be stateless and thread-safe. Multiple threads can send events at the same time.\n\n    Dispatcher dispatcher = Dispatchers.asynchronousUnsafe();\n\n##### Broadcast Ordered Dispatching #####\n\n * Listeners are called unordered\n * Events are published one after one\n * Many threads can enqueue an event at one time\n * A thread-pool is used to send each event to each subscriber\n\nThis strategy guarantees the order of events but calls listeners unordered. The goal of a broadcasting is to reach as fast as possible each listeners in the smallest amount of time. A thread-pool is used to handle subscriber's execution.\n\nThis type of dispatching is really useful when you don't care about ordering and want to publish fast and want your subscribers to be called as fast as possible.\n\nNote that when a thread publishes an event, it is enqueued. A thread is used to enqueue events one per one and fire this event concurrently to all subscribers. The publish method returns immediately, but for another event to be processed, all concurrent firing of the previous event must have finished.\n\nThis guarantees that all subscribers will be called concurrently, but they will all receive the events in the same order.\n\n    Dispatcher dispatcher = Dispatchers.broadcastOrdered();\n\n##### Broadcast Unordered Dispatching #####\n\n * Listeners are called unordered\n * Several events are published at the same time\n * Many threads can enqueue an event at one time\n * A thread-pool is used to send each event to each subscriber\n\nThis type of dispatching is really useful when you don't care about any ordering. Since the publish method does not block, any thread will be able to publish events really fast and a thread-pool is used to process them all, unordered.\n\nThus, subscribers taking a long time to execute don't affect publishing of other events to other subscribers.\n\n    Dispatcher dispatcher = Dispatchers.broadcastUnordered();\n\n##### Custom strategy #####\n\nYou can easily implelement and control your own dispatching strategy: simply look at the source code of `Dispatchers` to have more example. You can create a custom dispacther like this:\n\n    Dispatcher dispatcher = Dispatchers.custom(errorHandlerProvider, publishingExecutor, subscriberExecutor);\n\nExecutors are implementations of `java.util.concurrent.Executor`. The first one control the concurrency of the whole publishing process and the second one control the concurrency for calling a subscriber. The class `com.mycila.event.util.Executors` has two flavors that can help you for basic cases: \n\n * `Executors.immediate()`: execute the runnable immediately\n * `Executors.blocking()`: idem, but blocks so that only one thread can execute a subscriber at a time\n\n#### Integration ####\n\n##### Google Guice #####\n\nhttp://code.google.com/p/google-guice/\n\nMycila Event can be used without any IOC. But thanks to the powerful annotation support and injection listeners of [http://code.google.com/p/google-guice/ Google Guice], this dependency injection library integrates very well with Mycila Event.\n\n__Binding generated publishers__\n\n    public final class MyModule implements Module {\n        @Override\n        public void configure(Binder binder) {\n            MycilaEventGuice.bindPublisher(binder, MyCustomPublisher.class).in(Singleton.class);\n            MycilaEventGuice.bindPublisher(binder, MyCustomPublisher2.class).in(Singleton.class);\n            MycilaEventGuice.bindPublisher(binder, MyCustomPublisher3.class).in(Singleton.class);\n        }\n    \n        @Reference(Reachability.WEAK)\n        static interface MyCustomPublisher {\n            @Publish(topics = \"a/topic/path\")\n            void send(String... messages);\n        }\n    \n        static abstract class MyCustomPublisher2 {\n            @Publish(topics = \"a/topic/path\")\n            @Multiple\n            abstract void send(int event1, String... otherEvents);\n        }\n    \n        static abstract class MyCustomPublisher3 {\n            @Publish(topics = \"a/topic/path\")\n            @Multiple\n            abstract void send(int event1, Iterable\u003cString\u003e events);\n        }\n    }\n    \n    injector.getInstance(MyCustomPublisher.class).send(\"A\", \"cut\", \"message\", \"containing\", \"bad words\");\n    injector.getInstance(MyCustomPublisher2.class).send(1, \"A\", \"cut\", \"message\", \"containing\", \"bad words\", \"in varg\");\n    injector.getInstance(MyCustomPublisher3.class).send(1, Arrays.asList(\"A\", \"cut\", \"message\", \"containing\", \"bad words\", \"in list\"));\n\n__Automatically inject publishers and create subscriptions__\n\nSuppose you have a class like this:\n\n    public final class MyImpl implements MyClass {\n    \n        Publisher\u003cString\u003e publisher;\n    \n        @Subscribe(topics = \"a/topic/path\", eventType = String.class)\n        void subscribe(Event\u003cString\u003e event) {\n            System.out.println(\"(subscribe) Got: \" + event);\n        }\n    \n        @Subscribe(topics = \"a/topic/path\", eventType = String[].class)\n        void subscribeToList(Event\u003cString[]\u003e event) {\n            System.out.println(\"(subscribeToList) Got: \" + Arrays.toString(event.source()));\n        }\n    \n        @Subscribe(topics = \"a/topic/path\", eventType = Integer.class)\n        void subscribeToInts(Event\u003cInteger\u003e event) {\n            System.out.println(\"(subscribeToInts) Got: \" + event.source());\n        }\n    \n        @Publish(topics = \"a/topic/path\")\n        void publisher(Publisher\u003cString\u003e publisher) {\n            System.out.println(\"Publisher injected\");\n            publisher.publish(\"Hello from publisher !\");\n            this.publisher = publisher;\n        }\n    }\n\nWhen configuring Guice, simply put MycileEventModule like this:\n\n    Injector injector = Guice.createInjector(new MycilaEventGuiceModule(), new AbstractModule() {\n    \t@Override\n    \tpublic void configure(Binder binder) {\n    \t\tbinder.bind(MyClass.class).to(MyImpl.class);\n    \t}        \n    });\n\nAll the created instances by Guice will automatically discover MycilaEvent annotations and subscribing methods will be registered and publishers will be injected.\n\n[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/caad3334753cab502059a0ff8483e382 \"githalytics.com\")](http://githalytics.com/mycila/pubsub)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmathieucarbou%2Fpubsub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmathieucarbou%2Fpubsub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmathieucarbou%2Fpubsub/lists"}