SpringBoot AOP+ アノテーションを使用してマルチデータ ソースの切り替えを実装する際に発生する可能性のある問題


AOP+ アノテーション方式は複数のデータソースの原理を実現します

ThreadLocal のスレッド分離を通じて、スレッドをデータ ソース ID にバインドします。

  • 設定されていない場合は、デフォルトのデータソースが使用されます。
  • 設定されている場合、データ ソース ID に対応するデータ ソースを使用します (注: データ ソース ID は使用後にクリアする必要があります)

考えられる問題

シナリオ 1: 指定されたデータ ソースのリクエストでエラーが発生しました

問題の説明: 指定されたデータ ソースのリクエストでエラーが発生しましたが、データ ソースを指定しなかった後続のリクエストでは、指定されたデータ ソースが使用されました (デフォルトのデータ ソースを使用する必要があります)。

コード:

@Slf4j
@Aspect
@Order(-2)
@Component
public class DataSourceAspect {
    
    

    @Pointcut("@annotation(com.joker.datasource.aopannotation.DataSource) || @within(com.joker.datasource.aopannotation.DataSource)")
    public void run(){
    
    

    }

    @Around("run()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    
    
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 方法上获取
        // AnnotatedElementUtils.hasAnnotation()
        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
        if (Objects.isNull(dataSource)) {
    
    
            // 类上获取
            dataSource =  AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
        }
        // 设置数据源
        DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        Object obj = point.proceed();
        // 清除数据源
        DynamicDataSourceContextHolder.clearDataSourceType();
        return obj;
    }
}

問題分析:

  1. 指定されたデータ ソースのリクエストでエラーが発生したため、データ ソース ID のクリアが実行されず、現在のスレッド thread1 がまだデータ ソースにバインドされています。
  2. インターフェースリクエストで使用されるスレッドはスレッドプールで管理されるため、後続のスレッドthread1は引き続き他のリクエストに割り当てられる可能性があります。
  3. 後続のリクエストでスレッド thread1 が使用され、データ ソースが指定されていない場合、以前にバインドされたデータ ソースが引き続き使用され、間違ったデータ ソースが使用されます (本来はデフォルトのデータ ソースが使用されるはずです)。
  4. ただし、後続のリクエストでスレッド thread1 が使用され、データ ソースが指定されている場合は、問題はありません。

シナリオ 2: 指定されたデータ ソースのリクエストで新しいスレッドを使用する

問題の説明: 指定されたデータ ソースのリクエストで新しいスレッドが使用されるため、指定されたデータ ソースが無効になり、デフォルトのデータ ソースが使用されます。

問題分析: データ ソースはスレッドにバインドされているため、現在のスレッドが指定されたデータ ソースにバインドされている場合でも、リクエストで新しいスレッドが使用されている場合、新しいスレッドはデータ ソースにバインドされません (デフォルトのデータ ソースがデフォルトで使用されます)。新しいスレッドを使用する次のシナリオ:

  1. new Thread() によって作成された新しいスレッドが使用され、データ ソースは新しいスレッドで使用されます。
  2. スレッド プールは、スレッド プール内のスレッドを通じてデータ ソースを使用するために使用されます。
  3. Java8のlist.ParallelStream()を利用して並列処理(マルチスレッド処理)を行い、処理中にデータを利用する

おすすめ

転載: blog.csdn.net/JokerLJG/article/details/131406803