@Serviceアノテーションはどこに保持する必要がありますか?インターフェースまたは実装?


133

Springを使用してアプリケーションを開発しています。@Serviceアノテーションを使用する必要があります。私が持っているServiceIServiceImpl、そのようなことServiceImpl implements ServiceI@Service注釈をどこに保持するべきかについて、ここで混乱しています。

インターフェースまたは実装に注釈を付ける必要がありますか@Service?これら2つのアプローチの違いは何ですか?


これは、同様の投稿に対する私の答えです。stackoverflow.com
questions

回答:


140

インターフェースを使用しない@Component(または@Service、...)。インターフェースが役に立たなくなるためです。その理由を説明させてください。

クレーム1:インターフェースがある場合、そのインターフェースを注入ポイントタイプに使用します。

クレーム2:インターフェースの目的は、いくつかの実装によって実装できるコントラクトを定義することです。反対側には注入ポイントがあります(@Autowired)。インターフェイスを1つだけ、それを実装するクラスを1つだけ持つことは(IMHO)役に立たず、YAGNIに違反します。

事実:あなたが置くとき:

  • @Component(または@Service、...)インターフェースで、
  • それを実装する複数のクラスがあり、
  • 少なくとも2つのクラスがSpring Beanになる、および
  • タイプベースの注入のインターフェースを使用する注入ポイントがあります。

次に、NoUniqueBeanDefinitionException (または、環境、プロファイル、または修飾子を使用した非常に特別な構成設定があります...)

結論:インターフェイスで@Component(または@Service、...)を使用する場合、2つのクレインの少なくとも1つに違反する必要があります。したがって@Component、インターフェイスレベルで配置することは(いくつかのまれなシナリオを除いて)役に立たないと思います。


Spring-Data-JPAリポジトリーのインターフェースはまったく異なるものです


3
あなたが書いたものはとても興味深いです...それでどちらが正しい方法ですか?インターフェースに注釈を付けたり、実装にService注釈を付けたりしていませんか?Springはまだインターフェイスタイプを使用して自動配線できますか?これに対するあなたの答えは何ですか> stackoverflow.com/questions/12899372/…–
corlaez

3
質問があります。クラスが1つしか実装されていないのに、なぜサービスレイヤーのインターフェイスを作成する必要があるのですか。私は多くのプロジェクトを見てきましたが、それらにはコントローラー層、**サービス層servicInterfaceserviceInterfaceImpl)、およびリポジトリ層があります
Yubaraj 2017年

4
@Yubaraj:公平な点ですが、あなたの質問はかなり他のトピックに関するものです(私の回答では、私は仮定を採用しました:インターフェースがあり、質問はインターフェースを持つことではなく、注釈をどこに置くかについてです)。あなたの質問のために:2つの実装を持つことのないビジネスサービスクラスのためのインターフェースを持つ理由はほとんどありません。(BTW:他の人のためにAPIを構築していない限り、いつでもコードをリファクタリングして、必要なときにインターフェイスを導入できます)
Ralph

1
@Yubaraj、インターフェイスを使用すると、必要に応じて、軽量のインターフェイスベースのjdkプロキシをBeanに作成できます。インターフェースがない場合、Springはプロキシを作成するためにcglibを使用してBeanをサブクラス化または変更する必要があります。@Transactionalは、Beanへのプロキシが使用される例の1つです。AOPは別のものです。
Yoory N. 2017

1
実装クラスが1つしかない場合もありますが、インターフェースでメソッドを宣言することをお勧めします。仲間の開発者は、実装について心配することなく、宣言とドキュメントを見るだけで、利用可能なサービスを簡単に確認できます。
HFSDev

32

基本的には同様の注釈@Service@Repository@Componentなどが、それらはすべて同じ目的を果たします:

注釈ベースの構成とクラスパススキャンを使用する場合の自動検出。

私の経験から、私は常に@Serviceインターフェースまたは抽象的なクラスのアノテーション@Component@Repositoryそれらの実装のようなアノテーションを使用しています。@Componentこれらのクラスで使用しているアノテーションは、基本的な目的、単純なSpring Bean、その他何も提供しません。レイヤーで@Repository使用している注釈。DAOたとえば、データベースと通信する必要がある場合、トランザクションがある場合などです。

その@Serviceため、機能に応じて、およびその他のレイヤーでインターフェースに注釈を付けることをお勧めします。


10
アノテーション付きインターフェースとアノテーション付き実装の違いは何ですか?
TheKojuEffect 2013年

27
Spring docsから、「このアノテーションは@Componentの特殊化として機能し、クラスパススキャンを通じて実装クラスを自動検出できるようにします」と実装クラスで使用することを意図していることを示唆しています。
nbrooks、2015

1
- @TheKojuEffect、このポスト実装VS注釈インターフェースとの間の詳細差に説明stackoverflow.com/questions/3120143/...
マヘシュ

@ user3257644その投稿の回答によって提示された提案は、一般にすべての注釈ではなく、特に「@Transactional」注釈に関するものであることに注意してください。
ジョナサン

3
インターフェースの@serviceアノテーションは、他のステレオタイプアノテーションと同様に効果がありません。すべてのステレオタイプアノテーションは、抽象クラスまたは具象クラスのいずれかに配置する必要があります。
ビッグフット2017年

13

私が使用し@Component@Service@Controller@Repositoryだけ実装クラスではなくインターフェイスに注釈します。しかし@Autowired、インターフェースによる注釈はまだ私のために働いた。


7

@Serviceにアノテーションを付ける利点は、それがサービスであることのヒントを与えることです。デフォルトでこの注釈を継承する実装クラスがあるかどうかはわかりません。

反対に、Spring固有のアノテーションを使用して、インターフェースをSpringなどの特定のフレームワークに結合します。インターフェースは実装から切り離されているはずなので、フレームワーク固有のアノテーションやインターフェースのオブジェクト部分を使用することはお勧めしません。


1
私たちは皆、強い結合の議論を何度も聞いたと思いますが、注釈はjarなしでも存在する可能性があることを覚えておいてください。したがって、基本的に、結合が注釈にある限り、それを分離することができます。
Niels Bech Nielsen

1

Springの利点の1つは、サービス(またはその他)の実装を簡単に切り替えることができることです。そのためには、インターフェースに注釈を付け、次のように変数を宣言する必要があります。

@Autowired
private MyInterface myVariable;

ではなく:

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

最初のケースと同様に、注入する実装を一意にしてからアクティブ化できます(インターフェイスを実装するクラスは1つだけです)。2番目のケースでは、すべてのコードをリファクタリングする必要があります(新しいクラスの実装には別の名前があります)。結果として、アノテーションはできるだけインターフェース上にある必要があります。さらに、JDKプロキシはこれに最適です。ランタイムタイプはCGlibプロキシとは異なり、事前にわかっているため、アプリケーションの起動時に作成およびインスタンス化されます。


4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao 2018年

最初の例が機能するために、インターフェースに注釈を付ける必要はありません。@Service実装に注釈を付けて、インターフェースを自動配線することができます。Springは、このインターフェースを実装するオブジェクトをチェックします。
Marco

1

私は@Serviceあなたのクラスに入れますが、インターフェースの名前を注釈へのパラメータとして入れます例えば

interface ServiceOne {}

@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}

そうすることで、すべてのメリットが得られ、インターフェースを注入できますが、クラスを取得できます

@Autowired 
private ServiceOne serviceOne;

したがって、インターフェイスはSpringフレームワークに関連付けられておらず、クラスをいつでも変更でき、すべての注入ポイントを更新する必要はありません。

したがって、実装クラスを変更したい場合は、新しいクラスに注釈を付けて最初のクラスから削除するだけで済みますが、変更する必要があるのはそれだけです。クラスを注入すると、実装クラスを変更したいときに多くの作業が発生する可能性があります。


-1

簡単に言えば:

@Serviceは、サービス層のステレオタイプアノテーションです。

@Repositoryはのためのステレオタイプ注釈で永続化層。

@Componentは、アプリケーションコンテキストにオブジェクトのインスタンスを作成するようにSpringに指示するために使用される汎用ステレオタイプアノテーションです。インスタンスには任意の名前を定義できます。デフォルトはキャメルケースのクラス名です。


3
これらの注釈の意味は求められていませんが、それらをインターフェイスまたはその実装に配置する場所です。
nanosoft 2018年

-3

春の豆を作るために使用できる5つの注釈があります。回答を以下に記載してください。

本当にインターフェースが必要ですか?サービスインターフェイスごとに1つの実装を作成する場合は、それを避け、クラスのみを使用してください。もちろん、RMIがない場合、またはインターフェースプロキシが必要な場合。

@Repository-daoレイヤークラスを挿入するために使用します。

@Service-サービス層クラスを注入するために使用します。サービス層でも、dbトランザクション管理に@Transactionalアノテーションを使用する必要がある場合があります。

@Controller-Spring BeanとしてインジェクトするJSF管理対象Beanなどのフロントエンドレイヤーコントローラーに使用します。

@RestController-スプリングレストコントローラに使用します。これにより、毎回@ResponseBodyおよび@RequestBodyアノテーションをレストメソッドに配置することを回避できます。

@Component-コントローラ、サービス、またはdaoクラスではないSpring Beanを注入する必要がある場合、他のケースで使用します


はい、レイヤーの境界線(データアクセスレイヤーやサービスレイヤーなど)にインターフェイスが必要です。それらはそれらの層の実装を含むモジュールの疎結合を可能にします。それらがなければ、言及されたレイヤーのクライアントは具象タイプを知る必要があり、例えば、CachingDaoでBasicDaoを装飾したい場合、それらを変更する必要があります...
Igand
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.