Фабрика подключений к STOMP-клиенту представляет собой слой абстракции, отвечающий за создание, конфигурацию и управление жизненным циклом экземпляров клиента STOMP.js. В условиях веб-приложений, где требуется работа с WebSocket-соединениями, такой подход позволяет централизовать параметры подключения, унифицировать поведение клиента и упростить масштабирование логики взаимодействия с брокером сообщений.
STOMP.js предоставляет низкоуровневый API для работы с протоколом STOMP поверх WebSocket. В базовом сценарии разработчик напрямую создаёт экземпляр клиента и настраивает его:
При росте приложения такой подход приводит к дублированию конфигурации и расхождению поведения клиентов в разных частях системы. Фабрика подключений решает эту проблему, вводя единый механизм создания клиента.
Ключевая идея заключается в том, что создание STOMP-клиента становится функцией или модулем, который инкапсулирует:
Фабрика подключений чаще всего реализуется как функция, возвращающая
настроенный экземпляр Client из STOMP.js:
import { Client } from '@stomp/stompjs';
export function createStompClient(options = {}) {
const client = new Client({
brokerURL: options.brokerURL,
reconnectDelay: options.reconnectDelay ?? 5000,
heartbeatIncoming: options.heartbeatIncoming ?? 10000,
heartbeatOutgoing: options.heartbeatOutgoing ?? 10000,
});
return client;
}
На этом уровне фабрика уже решает задачу централизации параметров. Однако в реальных приложениях такой вариант является лишь отправной точкой.
Одним из ключевых аспектов STOMP.js является возможность
переопределения способа создания WebSocket через
webSocketFactory. Это особенно важно в случаях, когда
требуется:
Фабрика подключений может полностью управлять этим процессом:
import { Client } from '@stomp/stompjs';
export function createStompClient({ token, baseUrl }) {
return new Client({
webSocketFactory: () => {
const url = `${baseUrl}?token=${encodeURIComponent(token)}`;
return new WebSocket(url);
},
reconnectDelay: 5000,
});
}
В этом варианте фабрика перестаёт быть просто генератором конфигурации и становится точкой управления транспортным уровнем.
В современных веб-приложениях WebSocket-соединение почти всегда требует аутентификации. STOMP.js не навязывает способ передачи токенов, поэтому разработчик должен самостоятельно определить стратегию.
Фабрика подключений позволяет унифицировать добавление заголовков:
export function createStompClient({ getToken }) {
const client = new Client({
brokerURL: 'wss://example.com/ws',
connectHeaders: {
Authorization: `Bearer ${getToken()}`,
},
beforeConnect: () => {
client.connectHeaders.Authorization = `Bearer ${getToken()}`;
},
});
return client;
}
Использование beforeConnect позволяет динамически
обновлять токен перед каждой попыткой подключения, что критично при
работе с истекающими сессиями.
Фабрика может не только создавать клиента, но и контролировать его поведение после создания. В STOMP.js жизненный цикл включает этапы:
Фабрика может встроить стандартные обработчики событий:
export function createStompClient() {
const client = new Client({
brokerURL: 'wss://example.com/ws',
reconnectDelay: 5000,
});
client.onConn ect = (frame) => {
console.log('Connected:', frame.headers);
};
client.onStompEr ror = (frame) => {
console.error('Broker error:', frame.headers['message']);
};
client.onWebSocketCl ose = () => {
console.log('WebSocket closed');
};
return client;
}
Такой подход позволяет стандартизировать реакцию приложения на ключевые события без необходимости повторной настройки в каждом модуле.
Фабрика подключений часто используется для различения окружений:
Вместо разрозненной логики выбора URL в разных частях приложения, вся логика концентрируется внутри фабрики:
export function createStompClient() {
const env = process.env.NODE_ENV;
const brokerURL =
env === 'production'
? 'wss://prod.example.com/ws'
: 'ws://localhost:8080/ws';
return new Client({
brokerURL,
reconnectDelay: 3000,
});
}
Такой подход уменьшает вероятность ошибок конфигурации при деплое.
Более гибкий вариант предполагает, что фабрика принимает конфигурационный объект, но при этом применяет дефолтные значения и правила валидации:
export function createStompClient(config) {
const defaults = {
reconnectDelay: 5000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000,
};
const finalConfig = {
...defaults,
...config,
};
const client = new Client(finalConfig);
return client;
}
Такой подход обеспечивает баланс между гибкостью и контролем. Приложение получает возможность переопределять параметры, но базовые настройки остаются неизменными.
В сложных приложениях STOMP-клиент становится частью инфраструктуры, где требуется:
Фабрика позволяет встроить эти механизмы на этапе создания клиента:
export function createStompClient({ logger }) {
const client = new Client({
brokerURL: 'wss://example.com/ws',
});
client.onConn ect = () => {
logger.info('STOMP connected');
};
client.onStompEr ror = (frame) => {
logger.error('STOMP error', frame.body);
};
client.onWebSocketCl ose = () => {
logger.warn('WebSocket closed');
};
return client;
}
Таким образом, клиент перестаёт быть изолированным объектом и становится частью наблюдаемой системы.
Одним из ключевых преимуществ фабрики является контроль над тем, создаётся ли новый экземпляр клиента или используется существующий. Это влияет на:
Фабрика может реализовывать как создание нового клиента, так и кэширование:
let instance = null;
export function getStompClient() {
if (instance) {
return instance;
}
instance = new Client({
brokerURL: 'wss://example.com/ws',
reconnectDelay: 5000,
});
return instance;
}
Хотя это уже приближается к паттерну singleton, фабрика остаётся более гибким механизмом, так как может комбинировать оба подхода в зависимости от параметров.
В некоторых сценариях требуется пересоздание клиента при изменении параметров среды: смена пользователя, обновление токена, переключение контекста.
Фабрика позволяет реализовать такой сценарий явно:
let client = null;
export function resetStompClient(config) {
if (client) {
client.deactivate();
}
client = new Client(config);
return client;
}
Это обеспечивает контролируемое завершение старого соединения перед созданием нового, предотвращая утечки подписок и дублирование сообщений.
Фабрика подключений отделяет:
Такое разделение соответствует принципу единой ответственности. STOMP-клиент остаётся инфраструктурным объектом, а фабрика становится точкой сборки.
В результате код приложения получает предсказуемую структуру:
Фабрика подключений может быть расширена дополнительными слоями:
Такая архитектура превращает фабрику в инфраструктурный компонент, который управляет не только созданием клиента, но и всей логикой взаимодействия с брокером сообщений на уровне приложения.