web-dev-qa-db-ja.com

Spring @Autowiredフィールド-どのアクセス修飾子、プライベートまたはパッケージ-プライベート?

クラスのさまざまなフィールドに@Autowiredアノテーションを使用し、フィールドを設定できるセッターやコンストラクターを作成しなかったとします。

質問-アクセス修飾子は、privateまたはpackage-private(つまり、なし)とは何ですか?

例えば:

public class MyClass {
    @Autowired
    private MyService myService;
}

vs

public class MyClass {
    @Autowired
    MyService myService;
}

最初のケース(private fields)の場合、Springは、セッターがない場合でも、反射を使用してフィールドを配線します。

2番目のケース(package-privateフィールド)では、テスト目的でクラスを拡張する必要がある場合に、これらのフィールドにアクセスできるようになります(たとえば、モックを設定するため)。

したがって、どちらの場合も正常に機能しますが、特にテストに関して、どちらがより推奨されますか?

17
vikingsteve

最初のケースでは、フレームワークに応じてモックを注入することもできます。たとえば、Mockitoの@InjectMocksアノテーションを使用します。 SpringテストではReflectionTestUtils.setFieldもあります...

私は個人的にテスト目的でクラスをあまり変更するのが好きではないので、最初のケースに行きます。しかし、結局のところ、これはお好みのテストフレームワークに大きく依存します。

6
Simon Verhoeven

私は通常、フィールドをプライベートにし、セッターインジェクションを使用することを好みます。

public class MyClass {

    private MyService myService;

    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }
}   

サービスを@Autowiredにすることができますが、単体テスト用にモックされたインスタンスで設定されます。

7
trf

したがって、どちらの場合も正常に機能しますが、特にテストに関して、どちらがより推奨されますか?

プロパティはprivateである必要があると思います:

@Autowired
private MyService myService;

他のクラスがプロパティに直接アクセスできるようにするのではなく、プロパティへのアクセスを提供するgetterメソッドがあると常に便利です。

また、テストの目的で、private propertiesmocksの注入は、package-privateプロパティの注入と同じように機能します。

たとえば、Mockitoを使用すると、次のようにprivate MyServiceのモックをMyClassに挿入できます。

public class MyClassTest {

    @Mock
    MyService service;

    @InjectMocks
    MyClass serv = new MyClass();

    @Before
    public void init() {
    MockitoAnnotations.initMocks(this);
    }
}
6
Debojit Saikia

私は通常、プライベートフィールドやメソッドに@Autowiredを使用しません。 @Autowiredは、外部の誰かがこのフィールドを設定することを意味します。一方、「プライベート」とは、このクラス以外の誰もがそれを使用できないことを意味します。

JITコンパイラが何らかの方法でこのコードを最適化すると、@ Autowiredとprivateを混在させると理論的に問題が発生する可能性があります。 Javaメモリモデルの同時実行性に関連する問題である可能性があります。これは、本番環境でのみ発生し、再現できません。

Autowiredフィールドを少なくともパッケージが見えるようにします。無料のボーナスとして、トリックや回避策なしでユニットテストを書くことができます。

PDATE:さらに、Javaメモリモデル関連の可視性の競合を回避するために、volatileなどのフィールドを宣言します。Spring開発者は自動配線フィールドを機能させるためにいくつかのトリックを行いますアクセスを明示的に同期せずに、これらのトリックがどのハードウェアのどのJVMでもスムーズに機能するかどうかはわかりません。

2
30thh


いくつかの理由から、@ Autowiredフィールドでprivateを使用したいと思います。

  • これらのフィールドは、他のサービスクラスを使用するために、通常はサービスクラスで依存性注入に使用します。その場合、これらのフィールドを現在のクラスに保持したいと思います。
  • また、このクラスを拡張するとロジックが異なる可能性があるため、@ Autowiredフィールドの別の実装が必要になる可能性があります。したがって、package-privateではなくprivateになります。
  • さらに、リファクタリングするときは、パッケージプライベートフィールドが未使用のときに警告を表示しないため、そのようなフィールドが使用されなくなったことを確認するのに役立ちます(IDEがEclipseであると仮定すると、実際には他のIDEについてはわかりません)。
0