検索
ホームページJava&#&チュートリアルダボをシミュレートし、MQ 非同期呼び出しを行うには、rabbit mq を使用します。

最近、古いシステムを改修していて、その前のプロセスで、送信側と消費側でさまざまな設定が必要になるシナリオに遭遇しました。そこで、ふと @Reference アノテーションの形式を思い出しました。 dubbo は可能でしょうか? MQ を呼び出すのが同期インターフェースを呼び出すのと同じくらい便利で簡単になるように、どうすればよいでしょうか。一般に、達成すべき目標は、dubbo と同様に、コンシューマ側がインターフェイスを公開し (dubbo サービスによって定義されたインターフェイスを再利用して、dubbo サービスの作成を同期または MQ 非同期にすることもできます)、送信側がインジェクトします。オブジェクトはカスタム アノテーションを通じてメソッドを呼び出し、フレームワーク内で内部的に処理されます。その後、非同期 MQ フォームに変換され、コンシューマーに送信されます。

たとえば、サーバーには

public interface MqDemoService {
    void dealById(Long id);
}
という実装があります。

その中に:

@Slf4j
@Component("mqDemoServiceImpl")
@Service(version = "1.0.0")
public class MqDemoServiceImpl implements MqDemoService {
    @Override
    public void dealById(Long id) {
        log.info("执行findById方法");
    }
}

興味のある学生は自分でチェックしてみてください

その後、送信側

がカスタマイズされています 注:

@Slf4j是lombok注解
@Service是dubbo服务端注解

したがって、呼び出し元のコントローラーでは:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AsyncInvoker {
}

@AsyncInvoker によって注釈が付けられた属性 mqDemoService に注意してくださいこのアノテーションを介して挿入されたオブジェクトがメソッドを呼び出すと、それは mq を介して送信され、非同期呼び出しになります。

達成すべき目標は非常に明確です。すると、解決すべき問題は次のとおりです。 :

@Slf4j
@Controller
public class MqDemoController {
  @AsyncInvoker
  private MqDemoService mqDemoService;

  @RequestMapping(value = "/deal", method = RequestMethod.POST)
  public void deal() {
    mqDemoService.dealById(1L);
  }
}

1. 受信側が呼び出しメソッドを決定できるように、送信メッセージの形式を決定する方法

ここでは、まず Java リフレクション呼び出しの要件に従います。パラメーターは単に送信オブジェクトを定義します:

1,如何确定发送消息的格式,使消费端可以确定调用的方法
2,发送端中如何为注解@AsyncInvoker注释的对象注入实例
3,接收端中如何在接收到消息后调用对应接口的实现方法
4,多个消费服务如何区分mq队列.

2.送信側で @AsyncInvoker アノテーションが付けられたオブジェクトにインスタンスを挿入します

このシナリオでは、送信側は実装ではなく、コンシューマー側のインターフェイスのみを導入します。 では、@AsyncInvoker はどのようにオブジェクトを挿入するのでしょうか?

答えは動的プロキシです。

それでは、@AsyncInvoker によって注釈が付けられたオブジェクトを動的プロキシに注入する必要があることを Spring にどのように知らせるのでしょうか?

答えは、Spring の BeanPostProcessor インターフェースです。このインターフェースにより、Spring は前後にユーザー定義のロジックを挿入します。オブジェクトの作成についてはここでは説明しません。必要な場合は、Baidu で検索してください。コードは次のとおりです。

@Data
public class MqMethodMeta {
  //调用的接口名称(包括包名,用于反射)
  private String interfaceName;
  //调用的方法名
  private String methodName;
  //调用的方法的参数
  private Object[] args;
  //调用的方法的参数类型
  private String[] paramTypeNames;
}

3. メッセージを受信した後はどうでしょうか。 、対応するインターフェイスの実装メソッドを呼び出します

受信側で対応するインターフェイスを呼び出すのは非常に簡単で、コードに直接アクセスするために MqMethodMeta オブジェクトを取得するだけです:

@Slf4j
@Component
public class AsyncInvokerBeanProcessor implements BeanPostProcessor {
  //缓存生成的动态代理对象,用于多个Controller注入同一类型对象时使用.
  private final ConcurrentMap<string> proxyMap = new ConcurrentHashMap();

  //注入spring amqp处理mq的对象
  @Autowired
  private RabbitTemplate rabbitTemplate;

  //BeanPostProcessor接口方法,在spring创建每个实例前插入的用户自定义逻辑.这里我们需要的是在每个Controller对象创建的时候为其中的@AsyncInvoker注解对象注入动态代理.
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //获取该实例中的有@AsyncInvoker注解的field
    Field[] fields = bean.getClass().getDeclaredFields();
    for (Field field : fields) {
      try {
        if (!field.isAccessible()) {
          field.setAccessible(true);
        }
        AsyncInvoker asyncInvoker = field.getAnnotation(AsyncInvoker.class);
        if (asyncInvoker != null) {
          //创建代理对象,赋值给该feild
          Object value = createProxy(field.getType());
          if (value != null) {
            field.set(bean, value);
          }
        }
      } catch (Throwable e) {
        log.error("Failed to init remote mq service at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
      }
    }
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  private Object createProxy(Class clz) {
    String interfaceName;
    if (clz.isInterface()) {
      interfaceName = clz.getName();
    } else {
      throw new IllegalStateException("The @MqInvoker property type " + clz.getName() + " is not a interface.");
    }

    Object proxy = proxyMap.get(interfaceName);
    if (proxy == null) {
      Object newProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clz}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          log.debug("执行动态代理! method:{} ,args: {}", method, args);
          if (method.getParameters().length != 1 || !method.getParameters()[0].getType().equals(Long.class)) {
            throw new IllegalAccessException("MQ Service 目前仅支持单参数Long类型方法");
          }
          //动态代理中创建mq传输对象并发送.
          MqMethodMeta mqMethodMeta = new MqMethodMeta();
          mqMethodMeta.setInterfaceName(clz.getName());
          mqMethodMeta.setMethodName(method.getName());
          mqMethodMeta.setArgs(args);
          String[] paramTypeNames = new String[args.length];
          for (int i = 0; i <p>4。複数のコンシューマー サービスを区別するにはどうすればよいですか? </p>
<h2 id="ここでは-rabbit-のトピック-タイプ交換が使用されます"> ここでは、rabbit のトピック タイプ交換が使用されます。 </h2> まず、コンシューマー リスナーでキューとルートキーを設定します。 <p></p>
<pre class="brush:php;toolbar:false">@Slf4j
public class AsyncMethodListener implements ApplicationContextAware {
  private ApplicationContext applicationContext;

  @RabbitListener(bindings = @QueueBinding(
      value = @Queue(value = "${demo.mq.method.queue}", durable = "true"),
      exchange = @Exchange(value = "exchange.demo.web.adaptor", type = ExchangeTypes.TOPIC, durable = "true"),
      key = "${demo.mq.method.routekey}"
  ))
  public void messageHandle(@Payload MqMethodMeta message) {
    try {
      log.info("收到message: {}", message);
      Class clz = Class.forName(message.getInterfaceName());
      String methodName = message.getMethodName();
      Object[] args = message.getArgs();
      Class[] paramTypes = new Class[message.getParamTypeNames().length];
      for (int i = 0; i  は、設定ファイル:<h2></h2>たとえば、システム 1 の設定は次のとおりです:<p></p><pre class="brush:php;toolbar:false">@RabbitListener(bindings = @QueueBinding(
      value = @Queue(value = "${demo.mq.method.queue}", durable = "true"),
      exchange = @Exchange(value = "exchange.demo.web.adaptor", type = ExchangeTypes.TOPIC, durable = "true"),
      key = "${demo.mq.method.routekey}"
  ))

システム 2 の設定は次のとおりです:
${demo.mq.method.queue}
${demo.mq.method.routekey}

送信側のコードを見てください:

demo.mq.method.queue=com.demo.service.project1.#
demo.mq.method.routekey=com.demo.service.project1.#

ここで clz.getName()私たちのシステムには優れた下請け戦略があるため、システム 1 の clz.getName() は com.demo.service.project1 で始まる必要があります。たとえば、project1 の値がリスナーに送信されます。 clz.getName() は com.demo .service.project1.MqDemoService (「.#」は次の複数の識別子と一致します。これは、rabbitMQ のトピック タイプ交換の機能です)。

この時点で、私たちが望んでいた目標は、冒頭の達成は達成されました。今後は、mq を使用して非同期呼び出しを行う必要があります。同期メソッドのように使用できます。

Spring での mq の使用方法については、ここでは詳しく説明しません。ドキュメント:

demo.mq.method.queue=com.demo.service.project2.#
demo.mq.method.routekey=com.demo.service.project2.#

一連のデモ コードは、記録と参照用に後で提供されます

概要

この方法にはまだいくつかの問題があります。例:

//关注此处clz.getName(),用于处理问题4
rabbitTemplate.convertAndSend("exchange.demo.web.adaptor", clz.getName(), mqMethodMeta);

最初の質問は、対応するコードを使用した後に検討する必要があります。 2 番目の質問は主に、コンシューマがパラメータのタイプやその他の状況を変更した場合、再公開後に古いメッセージと互換性があるかどうかです。現時点ではこれに関する良いアイデアはありません。これは単なるブレインストーミング用です。

以上がダボをシミュレートし、MQ 非同期呼び出しを行うには、rabbit mq を使用します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Java開発のどの側面がプラットフォームに依存していますか?Java開発のどの側面がプラットフォームに依存していますか?Apr 26, 2025 am 12:19 AM

javadevelopmentisnotentirelylylypratform-IndopentDuetoseveralfactors.1)jvmvariationsaffectperformanceandbehavioracrossdifferentos.2)nativeLibrariesviajniintroducePlatform-specificissues.3)giaiasystemsdifferbeTioneplateplatifflics.4)

さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?Apr 26, 2025 am 12:15 AM

Javaコードは、さまざまなプラットフォームで実行するときにパフォーマンスの違いがあります。 1)JVMの実装と最適化戦略は、OracleJDKやOpenJDKなどとは異なります。 2)メモリ管理やスレッドスケジューリングなどのオペレーティングシステムの特性もパフォーマンスに影響します。 3)適切なJVMを選択し、JVMパラメーターとコード最適化を調整することにより、パフォーマンスを改善できます。

Javaのプラットフォームの独立性の制限は何ですか?Javaのプラットフォームの独立性の制限は何ですか?Apr 26, 2025 am 12:10 AM

java'splatformindepentedencehaslimitationsincludingporformanceoverhead、versioncompatibulisisues、changleSwithnativeLibraryIntegration、プラットフォーム固有の機能、およびjvminStallation/maintenation。

プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。Apr 26, 2025 am 12:08 AM

PlatformEndependEncealLowsProgramStorunonAnyPlatformWithOdification、whilecross-platformdevelopmentReadreessomeplatform-specificAdjustments.platformindependence、explifiedByjava、unableSiversAlexecutionButMayCompromperformance

ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?Apr 26, 2025 am 12:02 AM

jitcompalilationinjavaenhancesperformance whelemaintaining formindepence.1)itdynamicallyTrantesiNTODENATIVEMACHINECODEATRUNTIME、最適化されたコードを最適化すること、

Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Apr 25, 2025 am 12:23 AM

javaispopularforsoss-platformdesktopapplicationsduetoits "writeonce、runaynay" philosophy.1)itusesbytecodatiTatrunnanyjvm-adipplatform.2)ライブラリリケンディンガンドジャヴァフククレアティック - ルルクリス

Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Apr 25, 2025 am 12:22 AM

Javaでプラットフォーム固有のコードを作成する理由には、特定のオペレーティングシステム機能へのアクセス、特定のハードウェアとの対話、パフォーマンスの最適化が含まれます。 1)JNAまたはJNIを使​​用して、Windowsレジストリにアクセスします。 2)JNIを介してLinux固有のハードウェアドライバーと対話します。 3)金属を使用して、JNIを介してMacOSのゲームパフォーマンスを最適化します。それにもかかわらず、プラットフォーム固有のコードを書くことは、コードの移植性に影響を与え、複雑さを高め、パフォーマンスのオーバーヘッドとセキュリティのリスクをもたらす可能性があります。

プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?Apr 25, 2025 am 12:12 AM

Javaは、クラウドネイティブアプリケーション、マルチプラットフォームの展開、および言語間の相互運用性を通じて、プラットフォームの独立性をさらに強化します。 1)クラウドネイティブアプリケーションは、GraalvmとQuarkusを使用してスタートアップ速度を向上させます。 2)Javaは、埋め込みデバイス、モバイルデバイス、量子コンピューターに拡張されます。 3)Graalvmを通じて、JavaはPythonやJavaScriptなどの言語とシームレスに統合して、言語間の相互運用性を高めます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール