そのため、多くのチームが共通のサービスを使用し、共通のアーキテクチャに従っているプロジェクトに取り組んでいます。使用されているサービスの 1 つはメッセージングであり、現在は ActiveMQ を使用した JMS です。ほとんどすべてのチームは、メッセージの作成と送信に関する厳密な一連のルールに従う必要があります。つまり、すべてが pub-subscribe であり、送信されるメッセージは次のようなものです。
public class WorkDTO {
private String type;
private String subtype;
private String category;
private String jsonPayload; // converted custom Java object
}
「jsonPayload」は、すべてのチームが拡張する基本クラスから取得されるため、共通の属性があります。
したがって、基本的に JMS では、全員が常に同じ種類のメッセージを送信しますが、異なる ActiveMQ トピックに送信します。メッセージ (WorkDTO) が JMS 経由で送信される場合、最初に JSON オブジェクトに変換され、次に TextMessage で送信されます。
チームがトピックのサブスクライバーを作成する場合は常に、DefaultMessageListenerContainer を作成し、メッセージを受信するように適切に構成します (Java ベースの Spring 構成を使用しています)。基本的に、チームが定義するすべての DefaultMessageListenerContainer は、メッセージを受信する宛先とメッセージ ハンドラーを除いてほとんど同じです。
そのような場合、アノテーションを介してメッセージング構成をさらに抽象化する方法に誰もがどのようにアプローチするのだろうと思っていましたか? つまり、誰もがほぼ同じ要件に従う必要があるため、次のようなものが役立つ可能性があります。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Listener {
String destination();
boolean durable() default false;
long receiveTimeout() default -1; // -1 use JMS default
String defaultListenerMethod() default "handleMessage";
// more config details here
}
@Listener(destination="PX.Foo", durable=true)
public class FooListener {
private ObjectMapper mapper = new ObjectMapper(); // converts JSON Strings to Java Classes
public void handleMessage(TextMessage message){
String text = message.getText();
WorkDTO dto = mapper.readValue(text, WorkDto.class);
String payload = dto.getPayload();
String type = dto.getType();
String subType = dto.getSubType();
String category = dto.getCategory();
}
}
もちろん、 @Listener アノテーションを使用して DefaultMessageListenerContainer を構成する方法の部分は省略しました。BeanFactoryPostProcessor を調べて、必要なクラスを作成し、それらをアプリケーション コンテキストに追加しましたが、そのすべてを行う方法がわかりません。
私が質問する理由は、JMS/ActiveMQ から AMQP/RabbitMQ に切り替えており、アノテーションを使用してメッセージング構成をさらに抽象化したいからです。AMQP は JMS とは違うので、設定の詳細は少し異なります。AMQP から別のものに切り替えるとは思えません。
ここで、チームは宛先の名前と、サブスクリプションを永続化するかどうかを知るだけで済みます。
これはつい最近ふと頭に浮かんだことです。これについて何か考えはありますか?
ただし、過度に複雑なことはしたくないので、別の方法として、宛先とメッセージ ハンドラーを指定して事前構成済みの DefaultMessageListenerContainer を返す便利なメソッドを作成することもできます。
@Configuration
public class MyConfig{
@Autowired
private MessageConfigFactory configFactory;
@Bean
public DefaultMessageListenerContainer fooListenerContainer(){
return configFactory.getListenerContainer("PX.Foo", new FooListener(), true);
}
}
class MessageConfigFactory {
public DefaultMessageListenerContainer getListener(String destination, Object listener, boolean durable) {
DefaultMessageListenerContainer l = new DefaultMessageListenerContainer();
// configuration details here
return l;
}
}