ОК, так что эта версия кажется мне лучшей реализацией:
public class QueueBindingRegistry implements SmartLifecycle, InitializingBean {
private DefaultListableBeanFactory beanFactory;
private AmqpAdmin amqpAdmin;
private AbstractMessageListenerContainer container;
private Supplier<Map<Queue, Set<Binding>>> queueBindingSupplier = Collections::emptyMap;
private Map<Queue, Set<Binding>> queueBindings = new HashMap<>();
private boolean running;
public QueueBindingRegistry(AbstractMessageListenerContainer container) {
//so we can set queues before container is started
container.setAutoStartup(false);
this.container = container;
}
@Autowired
public void setBeanFactory(
DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Autowired
public void setAmqpAdmin(AmqpAdmin amqpAdmin) {
this.amqpAdmin = amqpAdmin;
}
public void setQueueBindingSupplier(
Supplier<Map<Queue, Set<Binding>>> queueBindingSupplier) {
this.queueBindingSupplier = queueBindingSupplier;
}
public void removeQueueNames(String... queueNames) {
container.removeQueueNames(queueNames);
Set<String> qNamesForRemoval = Set.of(queueNames);
Set<Queue> qForRemoval = queueBindings.keySet().stream()
.filter(q -> qNamesForRemoval.contains(q.getName()))
.collect(Collectors.toSet());
qForRemoval.forEach(queue ->
queueBindings.computeIfPresent(queue, (q, qb) -> {
qb.forEach(this::destroyBinding);
destroyQueue(q);
return null; //remove from registry
}));
}
public void addQueuesAndBindings(Map<Queue, Set<Binding>> queuesAndBindings) {
queuesAndBindings.entrySet().stream()
//remove queues that already exist
.filter(e -> queueBindings.keySet().stream()
.noneMatch(exq -> exq.getName().equals(e.getKey().getName())))
.forEach((e) -> {
Queue q = e.getKey();
Set<Binding> b = e.getValue();
registerQueue(q);
b.forEach(this::registerBinding);
container.addQueues(q);
queueBindings.put(q, b);
});
}
private void destroyQueue(Queue queue) {
beanFactory.destroySingleton(queue.getName());
amqpAdmin.deleteQueue(queue.getName());
}
private void destroyBinding(Binding binding) {
beanFactory.destroySingleton(getBindingBeanName(binding));
amqpAdmin.removeBinding(binding);
}
private void initQueueBindings() {
queueBindings.putAll(queueBindingSupplier.get());
queueBindings.forEach((q, bs) -> {
registerQueue(q);
bs.forEach(this::registerBinding);
});
Queue[] queues = getAllQueues(queueBindings);
container.setQueues(queues);
}
private Queue[] getAllQueues(Map<Queue, Set<Binding>> queueBindings) {
return queueBindings.keySet().toArray(new Queue[0]);
}
private String getBindingBeanName(Binding binding) {
return binding.getExchange() + "-" + binding.getRoutingKey() + "-" + binding.getDestination();
}
private void registerBinding(Binding binding) {
amqpAdmin.declareBinding(binding);
beanFactory.registerSingleton(getBindingBeanName(binding), binding);
}
private void registerQueue(Queue queue) {
amqpAdmin.declareQueue(queue);
beanFactory.registerSingleton(queue.getName(), queue);
}
@Override
public void start() {
initQueueBindings();
//run after queues are initiated
container.start();
running = true;
}
@Override
public void stop() {
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public void afterPropertiesSet() {
Assert.isTrue(amqpAdmin != null, "AmqpAdmin bean must be set.");
Assert.isTrue(beanFactory != null, "BeanRegistry bean must be set.");
Assert.isTrue(queueBindingSupplier != null, "QueueBindingSupplier cannot be null.");
}
}
и регистрация для динамической регистрации проста:
@Bean
public QueueBindingRegistry queueBindingRegistry(DirectMessageListenerContainer directContainer) {
QueueBindingRegistry queueBindingRegistry = new QueueBindingRegistry(directContainer);
Queue q1 = QueueBuilder
.nonDurable("a1")
.build();
Queue q2 = QueueBuilder
.nonDurable("q2")
.build();
queueBindingRegistry.setQueueBindingSupplier(() -> Map.of(
q1,
Set.of(
BindingBuilder.bind(q1).to(new TopicExchange("someEX1")).with("k1"),
BindingBuilder.bind(q1).to(new TopicExchange("someEX2")).with("k2")
),
q2,
Set.of(
BindingBuilder.bind(q2).to(new TopicExchange("someEX1")).with("z1"),
BindingBuilder.bind(q2).to(new TopicExchange("someEX2")).with("z2")
)
));
return queueBindingRegistry;
}
, и если вы хотите удалитьочереди и привязки во время выполнения:
public void testRemoval() {
System.out.println("Removing queue from registry");
queueBindingRegistry.removeQueueNames("q2");
Queue q2 = QueueBuilder
.nonDurable("q2")
.build();
var s = Map.of(
q2,
Set.of(
BindingBuilder.bind(q2).to(new TopicExchange("someEX1")).with("xxxx"),
BindingBuilder.bind(q2).to(new TopicExchange("someEX2")).with("xxx2")
));
queueBindingRegistry.addQueuesAndBindings(s);
}