質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • Java

    15059questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    783questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • DI (Dependence Injection)

    17questions

    DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Springの@AutowiredでString型をDIさせる方法

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 930

yoshihiro_yy

score 15

SpringMVCを利用しております。

各コンポーネントの中で、xmlで定義した定数のようなものを利用したいと思い、
application-config.xmlに

<bean id="processName" class="java.lang.String">
    <constructor-arg value="xxxx" />
</bean>


このように記述しBeanを定義し、これを各コンポーネント内で

@Autowired
private String processName;


このようにフィールドインジェクションを利用しDIをさせようとしたところ、以下エラーが発生し上手くいきませんでした。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

DIの候補で一致する型が複数(もしくは0?)件の場合に出るエラーだったかと思いますが、他にjava.lang.String型でBean定義をしていないのです。

その後試行錯誤していたところ、

@Autowired(required=false)
private String processName;


とすると、期待通りエラーも出ず「processName」に「xxxx」という文字列がDIされていました。
上記required=falseはAutowiredでDIさせるBeanが見つからなかった場合にエラーにしない設定だと思っていたのですが、これはどういう動きでしょうか?

上記の動作から、@Autowiredの動きですが

  1. 型から一致するBeanを探しDIさせる(required=falseが設定されていない場合ここで見つからなければ例外発生)
  2. 次に名前で一致するBeanを探しDIさせる
  3. それでも見つからない場合はnullの状態のままとする(DIさせない)

こういった動きなのでしょうか?

もしそうなのであれば、

@Qualifier("")
@Resource

でもDIさせられるかと思い

@Qualifier("processName")
private String processName;

@Resource
private String processName;

@Resource(name="processName")
private String processName;


こう試しましたが、これらも例外が発生し上手くDIさせられませんでした。
(xmlでbeanにQualifierで命名する方法が検索したのですがよく分からず・・・)

私の希望するDIとしては、

@Autowired(required=false)

これが最善策なのでしょうか?


 上記では駄目でした

質問投稿後も、まさかと思い色々試していたのですが

@Autowired(required=false)
private String processName;


これはあくまでも型で一致するBeanを引っ張って来ているだけのようでした。
てっきり変数名と一致するIDのBeanをDIしているのかと思っていました。
なので

@Autowired(required=false)
private String processNameaaaaa;


といったふうに変えてもDIされていて、
上記@Autowiredの記述の状態(変数名がprocessNameaaaaa)で

<bean id="processName" class="java.lang.String">
    <constructor-arg value="xxxx" />
</bean>
<bean id="testName" class="java.lang.String">
    <constructor-arg value="aaaa" />
</bean>


と、String型のbeanを複数定義したところ

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected single matching bean but found 2: processName,testName

と例外が発生してしまいました。

 そこで改めて以下のようにしたところ希望通りの動きになりました

@Autowired(required=false)
@Qualifier("processName")
private String processNameaaaaa;
<bean id="processName" class="java.lang.String">
    <constructor-arg value="xxxx" />
</bean>
<bean id="testName" class="java.lang.String">
    <constructor-arg value="aaaa" />
</bean>


上記だと問題なく「processNameaaaaa」には「xxxx」がDIされていました。
そうなってくると色々と理解ができないのですが

@Autowired(required=false)

これを設定した時点で型によるDIは失敗しているのかと思えば、型によるDIをしていたようですし、
併記する形で

@Qualifier("processName")

を記述したらprocessNameというIDのbeanをDIさせていますし、意味が分かりません。。。
なぜ

@Autowired
private String processNameaaaaa;

@Qualifier("processName")
private String processNameaaaaa;

@Autowired
@Qualifier("processName")
private String processNameaaaaa;

これらではDIさせられないのでしょうか・・・

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

@Autowiredが付与されたフィールドに対して、requiredを省略(=true)した場合、Spring用に設定したapplicationContext.xml、ないしはSpringBootの場合はConfiguration内で定義したBean定義の候補を1つ探して返します。

ところがjava.lang.Stringに対して何らかの定義をしていない場合は、バインドする候補がないため例外がスローされるので、検証された結果となります。

https://docs.spring.io/spring/docs/5.0.8.RELEASE/spring-framework-reference/core.html#beans-autowired-annotation より

By default, the autowiring fails whenever zero candidate beans are available; the default behavior is to treat annotated methods, constructors, and fields as indicating required dependencies.

デフォルトでは、Beanの候補となるものがなければAutowireは失敗する。(というのも)このデフォルト時の振る舞いは、(Autowiredで)注釈したメソッド・コンストラクタ・フィールドに対して、依存関係を明示しなければならない。

そのため、Stringに対して必ずBean定義をしなければならず、また、Stringがアプリケーション全体で1つということも非常に珍しいでしょうから、@Qualifiedを使って明示的に名前を付けておかないと、今度は1つの@AutowiredしたStringに対して複数の候補が上がってしまい、これもまたSpringが「どのBeanを紐づけてよいかわからない」となります。

…なお、余談ですが、StringやMap,Listなど、アプリケーション内で頻繁につかうJava標準のクラスをSpringのBean定義で使う場合は、それは同じクラスが何度も登場することになるので、常にQualifiedで命名宣言しないとならなくなり、扱いが大変になるでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/09 09:21

    ご質問の内容がAutowiredの仕様(挙動)についてなので、このコメントは回答にはなりませんが、
    Stringなどのフィールドに値を設定したい場合は、プロパティファイルに値を定義しておいてValueアノテーション(org.springframework.beans.factory.annotation.Value)で代入するというのも1つの方法かと思います。

    キャンセル

0

もしかすると Spring のバージョンで動作が異なるのかもしれませんが、以下で動作しました。
(Spring Framework 5.0.8.RELEASE で確認しています。)

@Autowired
private String hoge;

@Autowired
private String fuga;
<bean id="hoge" class="java.lang.String">
    <constructor-arg value="hoge" />
</bean>
<bean id="fuga" class="java.lang.String">
    <constructor-arg value="fuga" />
</bean>

@Autowiredは型によってインジェクト対象の Bean を特定しますが、候補が複数見つかった場合、名前による特定を試みます。
今回のようにフィールドインジェクションの場合は、フィールド変数名によって候補を特定します。

https://qiita.com/kazuki43zoo/items/4597476607cf921c1453

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Java

    15059questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    783questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • DI (Dependence Injection)

    17questions

    DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。