Статьи

EventBus от Guava — простой издатель / подписчик

Просматривая недавние дополнения к Google Guava Libraries Release 10, я заметил добавление EventBus. Это упрощенная реализация системы обмена сообщениями в стиле «публикация-подписка». Это похоже на модель публикации-подписки, предоставляемую JMS , однако сообщения остаются внутри приложения, а не передаются извне.

EventBus позволяет вам создавать потоки в вашей программе, на которые могут подписываться объекты; затем они будут получать сообщения, опубликованные в этих потоках. Хотя это межобъектное взаимодействие не особенно сложно воссоздать с использованием таких шаблонов, как синглтоны, EventBus обеспечивает особенно простой и легкий механизм. Синглтоны также усложняют наличие нескольких шин для событий одного типа, и

трудно проверить.

В качестве примера я собираюсь создать простую многопользовательскую программу чата с использованием сокетов, к которым несколько человек будут подключаться через telnet. Мы просто создадим EventBus, который будет служить каналом. Любые сообщения, которые пользователь отправляет в систему, будут опубликованы всем остальным пользователям.

Итак, вот наш объект UserThread:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class UserThread extends Thread {
    private Socket connection;
    private EventBus channel;
    private BufferedReader in;
    private PrintWriter out;
 
    public UserThread(Socket connection, EventBus channel) {
        this.connection = connection;
        this.channel = channel;
        try {
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            out = new PrintWriter(connection.getOutputStream(), true);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
 
    @Subscribe
    public void recieveMessage(String message) {
        if (out != null) {
            out.println(message);
        }
    }
 
    @Override
    public void run() {
        try {
            String input;
            while ((input = in.readLine()) != null) {
                channel.post(input);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        //reached eof
        channel.unregister(this)
        try {
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        in = null;
        out = null;
    }
}

Как видно, это просто простой многопоточный объект, который содержит EventBus, который служит каналом, и Socket пользователя. Затем метод run просто читает сокет и отправляет сообщение в канал, вызывая метод post в EventBus.

Получение сообщений затем осуществляется путем добавления открытого метода с аннотацией @Subscribe (см. Выше). Это сигнализирует EventBus вызвать этот метод после получения сообщения типа, указанного в аргументе метода. Здесь я отправляю строки, но можно использовать и другие объекты.

GOTCHA : метод, аннотированный @Subscribe, ДОЛЖЕН быть общедоступным.

Функция приема принимает сообщение и записывает его в соединение пользователя. Это, конечно, также отправит ответное сообщение, которое было отправлено исходному пользователю, поскольку объект UserThread сам получит опубликованное сообщение.

Все, что осталось, — это создать простой объект сервера, который прослушивает соединения и создает объекты UserThread по мере необходимости.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class EventBusChat {
    public static void main(String[] args) {
        EventBus channel = new EventBus();
        ServerSocket socket;
        try {
            socket = new ServerSocket(4444);
            while (true) {
                Socket connection = socket.accept();
                UserThread newUser = new UserThread(connection, channel);
                channel.register(newUser);
                newUser.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Как показано, это создает канал, принимает пользовательские соединения и регистрирует их в EventBus. Важный код, на который следует обратить внимание, — это вызов метода register с объектом UserThread в качестве аргумента. Этот вызов подписывает объект на EventBus и указывает, что он может обрабатывать сообщения.

После запуска сервера пользователи могут подключиться к серверу чата с помощью команды telnet:

1
telnet 127.0.0.1 4444

И если вы подключите несколько экземпляров, вы увидите, что любое отправленное сообщение передается другим экземплярам.

Посмотрев этот пример, вы можете спросить, как использовать EventBus. Очень хорошим примером может служить поддержание очень слабой связи между пользовательским интерфейсом и внутренним кодом. Пользовательский ввод будет генерировать сообщение, такое как изменение размера, потеря фокуса или закрытие. Бэкэнд-компоненты могут просто подписаться на эти события и иметь с ними дело соответствующим образом. Официальная документация также содержит множество других применений.

NB. EventBus не предназначен для общения издателя и подписчика общего назначения, это всего лишь пример взаимодействия API.

Оригинал: http://insightfullogic.com/blog/2011/oct/10/eventbus/

Ссылка: EventBus от Guava — Simple Publisher / Subscriber от нашего партнера JCG Андрея Андруневчина в блоге Java User Group из Львова .