免責事項
このツールは
、小さな血の
設計上の欠陥を克服する
方法として生まれました。 楽器の使用が他の理由によって決定される状況を想像することはほとんどできません。
背景
ある日、中年のWebアプリケーションの開発に接続しました。 コードはいくつかの場所でかなり乱雑で、さまざまな資格を持つ複数の開発者の活動の痕跡を残しており、実際の機能テストはありませんでした。 一つの言葉はレガシーです。
アプリケーションは、従来の3層スキームに従って実装されました。
- 持続性:休止状態。
- サービス:春。
- エンドポイント:Spring MVC:JSP、RESTful。
また、すべてのレベルで、ストレージレベルのエンティティ(以下、エンティティと呼びます)が使用されました。 このため、エンティティのプロパティの名前を変更するには、クライアントまたはJSPでコードを編集する必要があり、コントローラーが提供したJSONまたはJSPに何かを追加する必要がありました。テストの欠如。
エンティティにない値を表現のレベルにドラッグする方法は?
いくつかの方法を検討しました。
リスナーとインターセプター
リスナーと
インターセプターを使用すると、エンティティに追加のデータを追加できます。 場合によっては、それらの使用は正当化されますが、ストレージレベルのエンティティを、ストレージレベルとは関係のない構造やデータで詰まらせたくないです。
マッピング
拡張を必要とする各クラスから継承し、サービスレベルで既に必要なデータを使用して開始できます。 これは概念的に正しいパスです。ストレージレイヤーはクリーンに保たれ、コントローラーレイヤーは変更する必要がありません。 ただし、パフォーマンスの問題があり、
遅延読み込みは
遅延しなくなります。 マッパーはコントローラーが必要とするフィールドを認識せず、すべてを強制的にシフトします。 コントローラー側からマッパーを制御することは理論的には可能ですが、これはコントローラーコードを変更しない限り不可能です。
動的プロキシ
ちょっとした魔法:
package ru.bdm.reflection;
フードの下には何がありますか?
追加プロパティのインターフェイスクラスは動的に作成されます。
public interface FirstHolder{ Object getFirst(); } public interface SecondHolder{ Object getSecond(); }
AnyType
を継承し、
AnyType
および
AnyType
を実装するプロキシクラスが動的に作成されます。
AnyType
で定義された
AnyType
、
src
にリダイレクトされるプロキシ、
FirstHolder
および
SecondHolder
定義されたメソッドは、追加のプロパティを計算するロジックを含む
PropertyExtractor
にリダイレクトされます。
したがって、コントローラーのコードを変更することなく、ストレージレベルの本質を外部の構造やデータで詰まらせることなく、遅延読み込みの問題によるパフォーマンスの低下を招くことなく、ビューを拡張する機会を得ました。
これに対する料金はそれほど高くありませんでした。プロキシを介したプロパティへのアクセスは、直接よりも約150倍遅くなります。 これは、ツールを使用するときに考慮する必要があります。
アプリケーションの負荷は1秒あたり数件のリクエストのみで、リクエストごとに最大50のエンティティ(ページサイズ)が読み込まれたため、プロキシの損失の割合は無視できました。
Googleドライブからコードをダウンロードできます。