Czech

Czech

biubiu

フレームワークに関する面接質問 - 参考回答

フレームワーク面接質問 - 参考回答#

面接官:Spring フレームワークのシングルトン bean はスレッドセーフですか?#

候補者

うん!

スレッドセーフではありません。こうなります。

複数のユーザーが同時にサービスを要求すると、コンテナは各要求にスレッドを割り当てます。これにより、複数のスレッドがその要求に対応するビジネスロジック(メンバー関数)を同時に実行します。この処理ロジックの中でシングルトンの状態に対する変更がある場合(シングルトンのメンバー属性として現れる)、スレッド同期の問題を考慮する必要があります。

Spring フレームワークはシングルトン bean に対してマルチスレッドのラッピング処理を行っていません。シングルトン bean のスレッドセーフ性と同時実行の問題は、開発者自身が解決する必要があります。

例えば:プロジェクトで通常使用する Spring bean は不変の状態(例えば Service クラスや DAO クラス)であるため、ある程度の意味で Spring のシングルトン bean はスレッドセーフです。

もしあなたの bean が複数の状態を持つ場合(例えば View Model オブジェクト)、スレッドセーフを自分で保証する必要があります。最も単純な解決策は、多態性 bean のスコープを「singleton」から「prototype」に変更することです。

面接官:AOP とは何ですか?

候補者

AOP はアスペクト指向プログラミングで、Spring ではビジネスに関係のないが複数のオブジェクトに影響を与える共通の振る舞いやロジックを抽出し、共通モジュールを再利用し、結合度を下げるために使用されます。一般的には、共通のログ保存やトランザクション処理などが行われます。

面接官:あなたたちのプロジェクトで AOP を使用していますか?

候補者

私たちは当時、バックエンド管理システムで AOP を使用してシステムの操作ログを記録しました。

主な考え方は、AOP の周囲通知とポイントカット式を使用して、ログを記録するメソッドを見つけ、その周囲通知のパラメータを通じてリクエストメソッドのパラメータ(クラス情報、メソッド情報、アノテーション、リクエスト方法など)を取得し、これらのパラメータをデータベースに保存することです。

面接官:Spring のトランザクションはどのように実現されていますか?

候補者

Spring が実現するトランザクションの本質は AOP によるもので、メソッドの前後でインターセプトを行い、メソッドを実行する前にトランザクションを開始し、ターゲットメソッドの実行後に実行状況に応じてトランザクションをコミットまたはロールバックします。

面接官:Spring でトランザクションが無効になるシナリオは何ですか?

候補者

うん!これはプロジェクトで以前に遭遇したことがあります。考えてみますね。

まず一つ目は、メソッドで例外をキャッチして処理し、自分で例外を処理して投げなかった場合、トランザクションが無効になります。ですので、一般的には例外を処理した後、忘れずに外に投げる必要があります。

二つ目は、メソッドがチェック例外を投げる場合、エラーが発生するとトランザクションが無効になります。最後に、Spring のトランザクションのアノテーションである @Transactional に rollbackFor 属性を Exception として設定することで、どんな例外でもトランザクションがロールバックされます。

三つ目は、以前に遭遇したことがあるのですが、メソッドが public 修飾子でない場合もトランザクションが無効になります。

うん、これだけ思い出せました。

面接官:Spring の bean のライフサイクル

候補者

うん!このステップは結構多いです。以前にいくつかのソースコードを見たことがありますが、だいたいの流れはこんな感じです。

まず、非常に重要なクラスである BeanDefinition を通じて bean の定義情報を取得します。ここには bean のすべての情報がカプセル化されています。例えば、クラスの完全パス、遅延ロードかどうか、シングルトンかどうかなどの情報です。

bean を作成する際の最初のステップは、コンストラクタを呼び出して bean をインスタンス化することです。

次のステップは bean の依存性注入です。例えば、いくつかの set メソッドの注入、普段の開発で使用する @Autowire はこのステップで完了します。

三つ目のステップは Aware インターフェースの処理です。もしある bean が Aware インターフェースを実装している場合、そのメソッドをオーバーライドして実行します。

四つ目は bean の後処理器 BeanPostProcessor です。これは前処理器です。

五つ目は初期化メソッドです。例えば、InitializingBean インターフェースを実装するか、init-method タグや @PostConstruct をカスタマイズしたメソッドです。

六つ目は bean の後処理器 BeanPostProcessor を実行します。主に bean を強化するために使用され、ここでプロキシオブジェクトが生成される可能性があります。

最後のステップは bean を破棄することです。

面接官:Spring における循環参照

候補者

うん、わかりました。説明しますね。

循環依存:循環依存とは実際には循環参照のことで、二つ以上の bean が互いに持ち合って最終的に閉じたループを形成します。例えば、A が B に依存し、B が A に依存する場合です。

Spring では循環依存が存在することが許可されており、Spring フレームワークは三重キャッシュに基づいて大部分の循環依存を解決しています。

①一次キャッシュ:シングルトンプールで、完全なライフサイクルを経て初期化が完了した bean オブジェクトをキャッシュします。

②二次キャッシュ:初期の bean オブジェクト(ライフサイクルがまだ完了していない)をキャッシュします。

③三次キャッシュ:ObjectFactory をキャッシュします。これは特定のオブジェクトを作成するためのオブジェクトファクトリーを示します。

面接官:具体的な解決プロセスは明確ですか?

候補者

第一に、A オブジェクトをインスタンス化し、同時に ObjectFactory オブジェクトを三次キャッシュ singletonFactories に保存します。

第二に、A が初期化されるときに B オブジェクトが必要で、これが B の作成ロジックに進みます。

第三に、B がインスタンス化されると、ObjectFactory オブジェクトが三次キャッシュ singletonFactories に保存されます。

第四に、B は A を注入する必要があり、三次キャッシュから ObjectFactory を取得して A オブジェクトを生成し、同時に二次キャッシュに保存します。これは二つのケースがあり、一つは A の通常のオブジェクト、もう一つは A のプロキシオブジェクトで、どちらも ObjectFactory が対応するオブジェクトを生成できます。これが三次キャッシュの鍵です。

第五に、B は二次キャッシュ earlySingletonObjects から A オブジェクトを取得した後、正常に注入できます。B が作成され、一次キャッシュ singletonObjects に保存されます。

第六に、A オブジェクトの初期化に戻ります。B オブジェクトがすでに作成されているため、直接 B を注入できます。A が作成され、一次キャッシュ singletonObjects に保存されます。

第七に、二次キャッシュの一時オブジェクト A がクリアされます。

面接官:コンストラクタで循環依存が発生した場合、どう解決しますか?

候補者

bean のライフサイクルの中でコンストラクタが最初に実行されるため、Spring フレームワークはコンストラクタの依存性注入を解決できません。@Lazy 遅延ロードを使用して、必要なときに bean オブジェクトを作成することができます。

面接官:SpringMVC の実行フローは知っていますか?

候補者

うん、これは知っています。いくつかのステップに分かれています。

  1. ユーザーがリクエストをフロントコントローラー DispatcherServlet に送信します。これは調整センターです。

  2. DispatcherServlet がリクエストを受け取り、HandlerMapping(ハンドラーマッピング)を呼び出します。

  3. HandlerMapping が具体的なハンドラーを見つけ(XML 設定やアノテーション設定を検索可能)、ハンドラーオブジェクトとハンドラーインターセプター(あれば)を生成し、DispatcherServlet に返します。

  4. DispatcherServlet が HandlerAdapter(ハンドラーアダプター)を呼び出します。

  5. HandlerAdapter が適応された後、具体的なハンドラー(Handler/Controller)を呼び出します。

  6. Controller が実行を完了し、ModelAndView オブジェクトを返します。

  7. HandlerAdapter が Controller の実行結果 ModelAndView を DispatcherServlet に返します。

  8. DispatcherServlet が ModelAndView を ViewResolver(ビューリゾルバー)に渡します。

  9. ViewResolver が解析し、具体的な View(ビュー)を返します。

  10. DispatcherServlet が View に基づいてビューをレンダリングします(モデルデータをビューに埋め込みます)。

  11. DispatcherServlet がユーザーに応答します。

もちろん、現在の開発では、基本的にフロントエンドとバックエンドが分離されているため、ビューはなく、一般的にはハンドラー内で Response を使用して直接結果を返します。

面接官:Spring Boot の自動構成原理

候補者

うん、わかりました。これはこうなります。

Spring Boot プロジェクトのブートストラップクラスには @SpringBootApplication というアノテーションがあります。このアノテーションは三つのアノテーションをラップしています。具体的には:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

その中で@EnableAutoConfigurationは自動化構成を実現するためのコアアノテーションです。

このアノテーションは@Importアノテーションを通じて対応する構成セレクターをインポートします。重要なのは、内部でこのプロジェクトとこのプロジェクトが参照する Jar パッケージの classpath パス下のMETA-INF/spring.factoriesファイルに設定されたクラスの完全クラス名を読み取っていることです。

これらの構成クラスで定義された Bean は、条件アノテーションによって指定された条件に基づいてSpring コンテナにインポートされるかどうかが決まります。

一般的な条件判断には、@ConditionalOnClassのようなアノテーションがあり、対応する class ファイルが存在するかどうかを判断し、存在すればそのクラスをロードし、この構成クラスのすべての Bean を Spring コンテナに投入します。

面接官:Spring の一般的なアノテーションにはどのようなものがありますか?

候補者

うん、これはたくさんあります。

第一のカテゴリは:bean を宣言するもので、@Component@Service@Repository@Controller があります。

第二のカテゴリは:依存注入に関連するもので、@Autowired@Qualifier@Resource があります。

第三のカテゴリは:スコープを設定するもので、@Scope があります。

第四のカテゴリは:Spring 構成に関連するもので、@Configuration@ComponentScan@Bean があります。

第五のカテゴリは:AOP に関連する強化アノテーションで、@Aspect@Before@After@Around@Pointcut があります。

面接官:SpringMVC の一般的なアノテーションにはどのようなものがありますか?

候補者

うん、これもたくさんあります。

@RequestMapping:リクエストパスをマッピングするために使用されます;

@RequestBody:アノテーションは HTTP リクエストの JSON データを受け取り、JSON を Java オブジェクトに変換します;

@RequestParam:リクエストパラメータの名前を指定します;

@PathVariable:リクエストパスからリクエストパラメータを取得し(/user/{id})、メソッドの形式パラメータに渡します;@ResponseBody:アノテーションはコントローラーメソッドの戻りオブジェクトを JSON オブジェクトに変換してクライアントに応答します。@RequestHeader:指定されたリクエストヘッダーデータを取得します。また、@PostMapping@GetMapping などもあります。

面接官:Spring Boot の一般的なアノテーションにはどのようなものがありますか?

候補者

うん~~

Spring Boot のコアアノテーションは @SpringBootApplication で、いくつかのアノテーションで構成されています:

  • @SpringBootConfiguration@Configuration アノテーションを組み合わせて、構成ファイルの機能を実現します;
  • @EnableAutoConfiguration:自動構成機能を有効にし、特定の自動構成オプションを無効にすることもできます。
  • @ComponentScan:Spring コンポーネントスキャン

面接官:MyBatis の実行フロー

候補者

はい、これは知っていますが、ステップも多いです。

①MyBatis 構成ファイルを読み取ります:mybatis-config.xml が実行環境とマッピングファイルを読み込みます。

②SqlSessionFactory というセッションファクトリを構築します。プロジェクトには一つだけ必要で、シングルトンで、一般的には Spring が管理します。

③セッションファクトリが SqlSession オブジェクトを作成します。ここには SQL 文を実行するためのすべてのメソッドが含まれています。

④データベース操作のインターフェースである Executor が実行され、クエリキャッシュの維持も担当します。

⑤Executor インターフェースの実行メソッドには、マッピング情報をカプセル化した MappedStatement 型のパラメータがあります。

⑥入力パラメータのマッピング

⑦出力結果のマッピング

面接官:MyBatis は遅延ロードをサポートしていますか?

候補者

はい、サポートしています~

遅延ロードの意味は、データが必要なときにのみロードし、必要ないときにはデータをロードしないことです。

MyBatis は一対一の関連オブジェクトと一対多の関連集合オブジェクトの遅延ロードをサポートしています。

MyBatis 構成ファイルで、遅延ロードを有効にするかどうかを設定できます。lazyLoadingEnabled=true|false、デフォルトは無効です。

面接官:遅延ロードの基盤原理は知っていますか?

候補者

うん、考えてみますね。

遅延ロードは、主に CGLIB 動的プロキシを使用して実現されます。

第一に、CGLIB を使用してターゲットオブジェクトのプロキシオブジェクトを作成します。ここでのターゲットオブジェクトは遅延ロードが有効になっている mapper です。

第二に、ターゲットメソッドを呼び出すと、インターセプターの invoke メソッドに入ります。ターゲットメソッドが null 値であることがわかり、SQL クエリを実行します。

第三に、データを取得した後、set メソッドを呼び出して属性値を設定し、ターゲットメソッドを再度クエリすると、値が得られます。

面接官:MyBatis の一次キャッシュ、二次キャッシュを使用したことがありますか?

候補者

うん~~、使ったことがあります~

MyBatis の一次キャッシュ:PerpetualCache に基づく HashMap のローカルキャッシュで、そのストレージスコープは Session です。Session が flush または close されると、その Session 内のすべての Cache がクリアされます。デフォルトで一次キャッシュは有効です。

二次キャッシュは別途有効にする必要があります。

二次キャッシュは namespace と mapper のスコープに基づいて機能し、SQL セッションには依存しません。デフォルトでも PerpetualCache、HashMap を使用します。

二次キャッシュを有効にするには、グローバル設定ファイルとマッピングファイルで設定を有効にする必要があります。

面接官:MyBatis の二次キャッシュはいつキャッシュ内のデータをクリアしますか?

候補者

うん!!

あるスコープ(一次キャッシュ Session / 二次キャッシュ Namespaces)で追加、変更、削除操作が行われた場合、デフォルトでそのスコープ内のすべての select のキャッシュがクリアされます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。