0

私はJavaEE6 Webアプリケーションを持っており、WebSocketプロトコルを使用してブラウザーと通信します。ブラウザはさまざまな種類のメッセージを送信できます。サーバーのonMessageメソッドでは、メッセージの種類に応じて、特定のメッセージハンドラークラスにメッセージをルーティング(またはディスパッチ)したいと思います。サーブレット(@WebServlet( "/ there"))のメカニズムと同様に、アノテーションを介してこれらのメッセージハンドラーを構成または登録したいと思います。また、サーブレットと同様に、メッセージハンドラでCDIインジェクションを使用できるようにしたいと思います。

今のところ、MessageTypeアノテーション、MessageHandlerインターフェース、および3つの実装があります。

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageType
{
    String value();
}


public interface MessageHandler
{
    public void processMessage(String inputMesssage);
}


@MessageType("first")
public class FirstMessageHandler implements MessageHandler
{
    @Inject
    ResourceBundleProvider resourceBundleProvider;

    @Override
    public void processMessage(String inputMesssage)
    {
        System.out.println("FirstMessageHandler#processMessage: " + inputMesssage);
        System.out.println("InjectionTest: " + resourceBundleProvider.getValue("label.language"));
    }
}


@MessageType("second")
public class SecondMessageHandler implements MessageHandler
{
    @Override
    public void processMessage(String inputMesssage)
    {
        System.out.println("SecondMessageHandler#processMessage: " + inputMesssage);
    }
}


public class DefaultMessageHandler implements MessageHandler
{
    @Override
    public void processMessage(String inputMesssage)
    {
        System.out.println("DefaultMessageHandler#processMessage: " + inputMesssage);
    }
}

また、リフレクションを使用して、注釈付きメッセージハンドラーのクラスパスをスキャンし、それらをインスタンス化してマップに配置するクラスMessageDispatcherがあります。

@ApplicationScoped
public class MessageDispatcher
{
    private Map<String, MessageHandler> messageHandlerMap = new HashMap<String, MessageHandler>();

    @Inject
    DefaultMessageHandler defaultMessageHandler;

    public MessageDispatcher()
    {
        registerAnnotatedHandlers();
    }

    private void registerAnnotatedHandlers()
    {
        Reflections reflections = new Reflections("namespace");

        try
        {
            for (Class<?> annotatedClass : reflections.getTypesAnnotatedWith(MessageType.class))
            {
                String annotationValue = annotatedClass.getAnnotation(MessageType.class).value();

                for (Class<?> interfaceClass : annotatedClass.getInterfaces())
                    if (!annotationValue.isEmpty() && interfaceClass.equals(MessageHandler.class))
                        messageHandlerMap.put(annotationValue, (MessageHandler) annotatedClass.newInstance());
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }       
    }

    public MessageHandler getMessageHandler(String key)
    {
        MessageHandler messageHandler = messageHandlerMap.get(key);

        return messageHandler != null ? messageHandler : defaultMessageHandler;
    }
}

そして最後に、WebSocketサーブレットのonMessageメソッドで、受信メッセージからキーを抽出し、それをメッセージルーティングに使用します。

public synchronized void onMessage(String data)
{
    String[] message = data.split(":");

    // Choose the message handler from the message
    MessageHandler messageHandler = messageDispatcher.getMessageHandler(message[0]);

    // Process the message by the message handler
    messageHandler.processMessage(message[1]);
}

私の3つの着信サンプルメッセージは次のとおりです。

"first:Message to handle with FirstMessageHandler"
"second:Message to handle with SecondMessageHandler"
"third:Message to handle with DefaultMessageHandler"

これは正常に機能します。最初のメッセージと2番目のメッセージはそれぞれFirstMessageHandlerとSecondMessageHandlerによって処理されます。キー「third」を処理するために登録された他のハンドラーがないため、3番目のメッセージはデフォルトのメッセージハンドラーによって処理されます。

私の問題:メッセージハンドラーはJavaリフレクションを使用して作成されているため、インジェクションを使用できません。注釈処理とCDIインジェクションを「結婚」させる方法を知っている人はいますか?または、このアプローチはでたらめであり、そのための別の解決策があると誰かが思いますか?

よろしく
セバスチャン

4

3 に答える 3

1

これが私の最後のアプローチです。

私はPostConstructメソッドをMessageDispachterに使用し、そこですべてのメッセージハンドラーBeanを探します。これらのBeanのそれぞれについて、アノテーション値とBeanへの参照(Beanの作成も含まれます)を取得します。次に、アノテーション値とBean参照の両方をmessageHandlerMapに格納します。多くのCDI委任と傍受が関係していますが、それは機能します。

public class MessageDispatcher
{
    private Map<String, MessageHandler> messageHandlerMap = new HashMap<String, MessageHandler>();

    @Inject
    DefaultMessageHandler defaultMessageHandler;

    @Inject
    BeanManager beanManager;

    @PostConstruct
    public void registerHandlers()
    {
        Set<Bean<?>> messageHandlerBeans = beanManager.getBeans(MessageHandler.class, new MessageTypeLiteral());
        for (Bean<?> bean : messageHandlerBeans)
        {
            String key = bean.getBeanClass().getAnnotation(MessageType.class).value();

            if (!key.isEmpty())
            {
                CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
                MessageHandler messageHandler = (MessageHandler) beanManager.getReference(bean, MessageHandler.class, creationalContext);
                messageHandlerMap.put(key, messageHandler);
            }
        }
    }

    public MessageHandler getMessageHandler(String key)
    {
        MessageHandler messageHandler = (MessageHandler) messageHandlerMap.get(key);
        return messageHandler != null ? messageHandler : defaultMessageHandler;
    }
}


@Documented
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface MessageType
{
    @Nonbinding
    String value();
}


@SuppressWarnings("all")
public class MessageTypeLiteral extends AnnotationLiteral<MessageType> implements MessageType
{
    private static final long serialVersionUID = 1L;

    @Override
    public String value()
    {
        return "";
    }
}


public class DefaultMessageHandler implements MessageHandler
{
    @Inject
    ResourceBundleProvider resourceBundleProvider;

    @Override
    public void processMessage(String inputMesssage)
    {
...


@MessageType("first")
public class FirstMessageHandler implements MessageHandler
{
    @Inject
    ResourceBundleProvider resourceBundleProvider;

    @Override
    public void processMessage(String inputMesssage)
    {
...

@NonBindingアノテーション内のアノテーションは、実際のアノテーション値(ここではxxx)に@MessageType関係なくアノテーションが付けられたすべてのBeanを見つけるために重要であるように思われます。@MessageType("xxx")

これが重要なことを説明することを願っています。詳細については私に聞いてください

セバスチャン

于 2012-10-30T18:49:55.670 に答える
0

これに対する最も簡単な解決策は、持っているものを保持し、スキャンが不要なため削除し、アノテーションを修飾子に変更して、修飾子を使用してCDIイベントを発生させることだと思います(作成する必要があります値がバインドされているため、3つの異なる修飾子のそれぞれのAnnotationLiteral)とペイロードとしてのメッセージ。

必要に応じて詳しく説明します。

于 2012-10-26T04:30:14.700 に答える
0

メンバーを含む修飾子を使用してCDIイベントを動的に起動するのを確認および調整 します。これは、実行時の決定によってサービスを動的に実行時に選択するためのCDIの方法です。TypeEnumは文字列にすることもできます。

于 2017-09-07T16:49:24.553 に答える