Spring @Autowiredの使用法を理解する


309

Spring Autowiredアノテーションを理解するために、Spring 3.0.xリファレンスドキュメントを読んでいます。

3.9.2 @Autowiredおよび@Inject

以下の例が理解できません。それを機能させるために、XMLで何かをする必要がありますか?

例1

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

例2

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
                    CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

同じインターフェイスを実装し、同じクラスを使用して、2つのクラスを自動配線するにはどうすればよいですか?

例:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

    draw(){
        color.design(); 
    } 
}

どの設計方法が呼び出されますか?BlueではなくRedクラスのデザインメソッドが呼び出されるようにするにはどうすればよいですか?

回答:


542

TL; DR

@Autowiredアノテーションは、XMLファイル(またはその他の方法)で自分で配線を行う必要をなくし、どこに注入する必要があるかを見つけて、それを実行するだけです。

完全な説明

@Autowired注釈は、あなたが他の場所で注入するかの設定をスキップすることができますし、あなたのためだけにそれをしません。パッケージがcom.mycompany.movies次のタグをXML(アプリケーションコンテキストファイル)に配置する必要があると仮定します。

<context:component-scan base-package="com.mycompany.movies" />

このタグは自動スキャンを実行します。Beanになる必要がある各クラスに@Component(単純なBeanの場合)または@Controller(サーブレットコントロールの場合)または@RepositoryDAOクラスの場合)などの正しいアノテーションが付けられ、これらのクラスがパッケージの下のどこかにあると仮定するとcom.mycompany.movies、Springはこれらすべてを見つけて作成しますそれぞれに豆。これは、クラスの2回のスキャンで行われます。最初にBeanになる必要があるクラスを検索し、実行する必要があるインジェクションをマップし、2回目のスキャンでBeanをインジェクトします。もちろん、より伝統的なXMLファイルで、または@Configurationクラス(または3つの任意の組み合わせ)でBeanを定義できます。

@Autowired注釈は、注入が発生する必要が春を告げます。メソッドsetMovieFinderに配置すると、Beanを注入する必要があることが(プレフィックスset+ @Autowiredアノテーションによって)理解されます。2回目のスキャンで、SpringはタイプBeanを検索し、MovieFinderそのようなBeanを見つけた場合、このメソッドに注入します。そのようなBeanが2つ見つかった場合は、Exception。を回避するExceptionには、@Qualifierアノテーションを使用して、次の方法で2つのBeanのどちらに注入するかを通知します。

@Qualifier("redBean")
class Red implements Color {
   // Class code here
}

@Qualifier("blueBean")
class Blue implements Color {
   // Class code here
}

または、XMLでBeanを宣言したい場合は、次のようになります。

<bean id="redBean" class="com.mycompany.movies.Red"/>

<bean id="blueBean" class="com.mycompany.movies.Blue"/>

@Autowired宣言、あなたも追加する必要が@Qualifier注入する2色豆のどの伝えるために:

@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
  this.color = color;
}

2つのアノテーション(the @Autowired@Qualifier)を使用したくない場合は@Resource、これらを組み合わせて使用できます。

@Resource(name="redBean")
public void setColor(Color color) {
  this.color = color;
}

@Resource(あなたはこの回答の最初のコメントでそれについていくつかの余分なデータを読み取ることができます)あなたに2つの注釈の使用を惜しみ、代わりにあなただけのいずれかを使用します。

さらに2つのコメントを追加します。

  1. Spring固有ではなく標準の一部であるため、@Inject代わりにを使用することをお勧めします。@AutowiredJSR-330
  2. 別の良い方法は、メソッドの代わりにコンストラクタに@Inject/ を置く@Autowiredことです。コンストラクターに配置すると、アプリケーションを起動しようとしたときに、注入されたBeanがnullではなく、すぐに失敗することを検証し、NullPointerException実際にBeanを使用する必要がある場合を回避できます。

更新:画像を完成させるために、クラスに関する新しい質問を作成しました@Configuration


6
ちょうどあなたの素晴らしい答えを完成させるために: '@Resource'はJSR-250標準の一部であり、単純な注入に加えて追加のセマンティクスがあります( '@Autowired'はSpringからのものであり、 '@ Inject'はJSR-330):)
イグナシオ・ルビオ2014

MovieFinderがインターフェースであり、MovieFinderImpl(bean id = movieFinder)のBean がある場合、Springはタイプまたは名前で自動注入しますか?
Jaskey

@jaskey-使用するかどうかによって異なります@Qualifier。行う場合-名前で、そうでない場合-タイプで。タイプ別MovieFinderは、コンテキスト内にタイプのBeanが1つしかない場合にのみ機能します。1を超えると、例外が発生します。
Avi 2015

@Avi、素晴らしい答え。しかし、例2のメソッドで@Autowiredアノテーションがどのように機能するかは理解できません。これは初期化中ですが、技術的にはセッターではありませんprepareMovieRecommender
Karan Chadha 2017

@KaranChadha- @Autowiredはコンストラクタでも機能します。必要な依存関係を見つけ、それらをコンストラクターに注入します。
Avi

21

この例では、「同じインターフェースを実装するクラス」を示していません。MovieCatalogはタイプでCustomerPreferenceDaoあり、別のタイプです。春は簡単にそれらを区別することができます。

Spring 2.xでは、Beanのワイヤリングは、ほとんどがBean IDまたは名前を介して行われていました。これは引き続きSpring 3.xでサポートされていますが、多くの場合、特定のタイプのBeanのインスタンスが1つあります。ほとんどのサービスはシングルトンです。それらの名前を作成するのは面倒です。したがって、Springは「タイプ別の自動接続」をサポートし始めました。

例が示すのは、フィールド、メソッド、およびコンストラクターにBeanを注入するために使用できるさまざまな方法です。

各Beanで完全修飾クラス名を指定する必要があるため、XMLには既にSpringが必要とするすべての情報が含まれています。ただし、インターフェイスには少し注意する必要があります。

この自動配線は失敗します:

 @Autowired
 public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }

Javaはパラメーター名をバイトコードに保持しないため、Springは2つのBeanを区別できなくなりました。修正は使用すること@Qualifierです:

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }

@AaronDigullaよかった。しかし、私はあなたが関数をどのように呼び出すのか知りたいのですが、この関数を呼び出すためprepareにどのパラメータが使用されますか?
グエンクアンアン2017

@NguyenQuangAnhメソッドを呼び出していません。Beanが作成されたときにSpringが実行します。これは、@Autowiredフィールドが挿入されたときに正確に発生します。その後、Springはパラメーターが必要であることを認識し、パラメーターを見つけるためにフィールド注入に使用されるのと同じルールを使用します。
アーロンディグラ2017

5

はい。Bean(つまりクラス)を定義するようにSpringサーブレットコンテキストxmlファイルを構成して、自動インジェクションを実行できるようにすることができます。ただし、Springを起動して実行するには他の構成を行う必要があることに注意してください。そのための最良の方法は、チュートリアルの基礎を踏襲することです。

Springをおそらく構成したら、上記の例1のSpringサーブレットコンテキストxmlファイルで次の操作を行うことができます(com.movi​​esのパッケージ名を、実際のパッケージ名に置き換えてください。これがサードパーティの場合クラス、適切なjarファイルがクラスパスにあることを確認してください):

<beans:bean id="movieFinder" class="com.movies.MovieFinder" />

または、MovieFinderクラスにプリミティブ値を持つコンストラクタがある場合は、次のようにすることができます。

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg value="100" />
</beans:bean>

または、MovieFinderクラスに別のクラスを予期するコンストラクターがある場合は、次のようにすることができます。

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg ref="otherBeanRef" />
</beans:bean>

...ここで、「otherBeanRef」は、予期されるクラスへの参照を持つ別のBeanです。


4
XML内のすべての配線を定義するだけの全体的なアイデアミス@Autowired
アビ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.