記事検索

検索ワードを入力してください。
Sky Tech Blog
【Spring Framework】カスタムコンテキストの​利用

【Spring Framework】カスタムコンテキストの​利用

Spring Frameworkで独自のコンテキスト(カスタムコンテキスト)情報を実行スレッド内で横断的に参照したいケースに対応するため、ThreadLocalを使用した「カスタムコンテキストの作成および、利用方法」について紹介します。

はじめに

Spring FrameworkはJavaプラットフォーム上で動作するアプリケーションフレームワークとなり、アプリケーション開発を効率的にできるよう主に下記機能を提供しております。

機能 詳細
依存性注入(DI) クラス外から依存するオブジェクトを注入することで、クラス間が疎結合な設計が可能となり、テストや拡張が容易となる。
アスペクト指向プログラミング(AOP) ログ出力やトランザクション管理など、異なる関数などで行う共通処理を分離し、一元管理が可能。
データアクセス データベース操作を簡単に行えるよう、JDBC・JPA・Hibernateなどをサポート。
Webフレームワーク リクエストのルーティングや画面表示、ビジネスロジックがそれぞれ独立。アノテーションなども充実しており、APIなどを簡単に実装可能。
セキュリティ 認証・認可機能を提供。また、セッション管理やCSRFなどのWeb攻撃に対する保護機能も提供。

また、アプリケーション内の状態や情報を管理を容易にするため様々なコンテキスト(ApplicationContextなど)を提供しており、その中には、実行スレッド内で横断的に参照できる下記のコンテキスト保持クラス(以降、ContextHolder)も提供されています。

クラス 概要
RequestContextHolder Webリクエスト情報を保持
SecurityContextHolder ログインしたユーザーの認証情報を保持

しかし、各種アプリケーション開発では、独自のコンテキスト(以降、カスタムコンテキスト)情報を実行スレッド内で横断的に参照したいケースがあるかと思います。
(関数の引数で引き回したり、参照箇所で都度取得する事も可能ではありますが、保守性や拡張性に乏しい状況になるかと思います。)

当記事ではThreadLocalを使用した「カスタムコンテキストの作成および、利用方法」について紹介いたします。

カスタムコンテキストの​作成および、​利用方​法

今回の例としては、「リクエストを要求したユーザーの詳細情報」を保持するコンテキストの作成および、利用する方法についてコード例を交えて下記の流れでご説明します。

  • カスタムコンテキストの定義
  • カスタムコンテキストへデータ登録
  • カスタムコンテキストの参照

① カスタムコンテキストの​定義

UserContextクラス

保持したいユーザーの詳細情報を定義した「UserContext」クラスを作成します。

@Getter
@Builder
public class UserContext {
  private String userId;
  private String userName;
  private String mailAddress;
}

UserContextHolderクラス

ThreadLocal変数を使用して、ユーザー詳細情報を管理する「UserContextHolder」クラスを作成します。

public class UserContextHolder {
    private static final ThreadLocal userContext = new ThreadLocal();
    public static UserContext get() {
        var context = userContext.get();
        if (Objects.isNull(context)) {
            return UserContext.builder().build();
        }
        return context;
    }
    public static void set(UserContext context) {
        userContext.set(context);
    }
    public static void clear() {
        userContext.remove();
    }
}

② カスタムコンテキストへ​データ登録

UserContextFilterの​作成

リクエスト単位でユーザーコンテキストを設定する「UserContextFilter」クラスを作成します。
当Filter層にて、リクエスト処理前にユーザーコンテキストを設定し、リクエスト処理後にユーザーコンテキストをクリアしております。

@Component
public class UserContextFilter extends OncePerRequestFilter {
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {
    try {
      beforeRequest(request);
      filterChain.doFilter(request, response);
    } finally {
      afterRequest(request);
    }
  }
  private void beforeRequest(HttpServletRequest request) {
    // ユーザー情報を設定
    var userContext = UserContext.builder()
        .userId("★ユーザーID★")
        .userName("★ユーザー名★")
        .mailAddress("★メールアドレス★")
        .build();
    UserContextHolder.set(userContext);
  }
  protected void afterRequest(HttpServletRequest request) {
    UserContextHolder.clear();
  }
}

UserContextFilterクラスの​登録

上記で作成した「UserContextFilter」クラスをDIコンテナへ登録します。
(Filterの実行順番を制御する場合は、「registrationBean.setOrder」を使用してください。)

@RequiredArgsConstructor
@Configuration
public class FilterConfiguration {
  private final UserContextFilter requestUserContextFilter;
  @Bean
  public FilterRegistrationBean registUserContextFilter() {
    var registrationBean = new FilterRegistrationBean<>(requestUserContextFilter);
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
  }
}

③ カスタムコンテキストの​参照

「UserContext」を参照したいクラスでの実装例となります。
この例ではCotroller層でユーザーコンテキストを参照しておりますが、Service層やRepository層など、必要な箇所で参照する事が可能です。

@RestController
@RequestMapping("/api")
public class ExampleController extends ControllerParent {
  @PostMapping("/example")
  public void example(
      HttpServletRequest request,
      HttpServletResponse response) throws Exception {
    // ユーザーコンテキスト取得
    var userContext = UserContextHolder.get();
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // ユーザーコンテキストを使用した処理
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  }
}

おわりに

今回の例では、実行スレッドで横断的に参照できるカスタムコンテキストの作成方法について紹介させていただきました。
次回は、実行スレッドから別スレッドに対してコンテキストを引き継ぐ方法についてご紹介できればと思います。


\シェアをお願いします!/
  • X
  • Facebook
  • LINE
キャリア採用募集中!

入社後にスキルアップを目指す若手の方も、ご自身の経験を幅広いフィールドで生かしたいベテランの方も、お一人おひとりの経験に応じたキャリア採用を行っています。

Sky株式会社のソフトウェア開発や製品、採用に関するお問い合わせについては、下記のリンクをご確認ください。
お問い合わせ
ホーム