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

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

新規登録して質問してみよう
ただいま回答率
85.50%
DI (Dependence Injection)

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

Java

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

Spring

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

Q&A

2回答

5483閲覧

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

yoshihiro_yy

総合スコア27

DI (Dependence Injection)

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

Java

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

Spring

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

0グッド

1クリップ

投稿2018/08/08 11:03

編集2022/01/12 10:55

SpringMVCを利用しております。

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

xml

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

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

Java

1@Autowired 2private 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定義をしていないのです。

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

Java

1@Autowired(required=false) 2private 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させられるかと思い

Java

1@Qualifier("processName") 2private String processName; 3 4@Resource 5private String processName; 6 7@Resource(name="processName") 8private String processName;

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

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

@Autowired(required=false)

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


上記では駄目でした

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

Java

1@Autowired(required=false) 2private String processName;

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

Java

1@Autowired(required=false) 2private String processNameaaaaa;

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

xml

1<bean id="processName" class="java.lang.String"> 2 <constructor-arg value="xxxx" /> 3</bean> 4<bean id="testName" class="java.lang.String"> 5 <constructor-arg value="aaaa" /> 6</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

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

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

Java

1@Autowired(required=false) 2@Qualifier("processName") 3private String processNameaaaaa;

xml

1<bean id="processName" class="java.lang.String"> 2 <constructor-arg value="xxxx" /> 3</bean> 4<bean id="testName" class="java.lang.String"> 5 <constructor-arg value="aaaa" /> 6</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させられないのでしょうか・・・

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

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

java

1@Autowired 2private String hoge; 3 4@Autowired 5private String fuga;

xml

1<bean id="hoge" class="java.lang.String"> 2 <constructor-arg value="hoge" /> 3</bean> 4<bean id="fuga" class="java.lang.String"> 5 <constructor-arg value="fuga" /> 6</bean>

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

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

投稿2018/08/11 05:58

d-yosh

総合スコア270

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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 00:10

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubytomato

2018/08/09 00:21

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問