[解決済み] Spring の @Autowired フィールドが NULL になっているのはなぜですか?
質問
注:これはよくある問題に対する定型的な回答であることを意図しています。
私は、Springの
@Service
クラス (
MileageFeeCalculator
を持つ)。
@Autowired
フィールド(
rateService
) が、そのフィールドは
null
を使おうとすると ログを見ると、どちらも
MileageFeeCalculator
ビーンと
MileageRateService
ビーンが作成されるのですが
NullPointerException
を呼び出そうとするたびに
mileageCharge
メソッドをサービスビーンに追加しました。なぜSpringはフィールドを自動配線しないのでしょうか?
コントローラクラスです。
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator();
return calc.mileageCharge(miles);
}
}
サービスクラスです。
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- should be autowired, is null
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- throws NPE
}
}
で自動配線されるべきサービスビーン。
MileageFeeCalculator
が、そうなっていない。
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
を試したところ
GET /mileage/3
このような例外が発生します。
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...
解決方法は?
アノテーションされたフィールド
@Autowired
は
null
のコピーについてSpringが知らないからです。
MileageFeeCalculator
で作成した
new
で、自動配線することを知りませんでした。
SpringのIoC(Inversion of Control)コンテナ
は3つの主要な論理的なコンポーネントを持っています: レジストリ (これは
ApplicationContext
)のコンポーネント(Bean)をアプリケーションで使用できるようにするシステム、オブジェクトの依存関係をコンテキスト内のBeanと照合して注入するconfigurerシステム、多くの異なるBeanの構成を見て、必要な順序でインスタンス化し構成する方法を決定できる依存関係ソルバーがあります。
IoCコンテナは魔法ではないので、何らかの方法で知らせない限り、Javaオブジェクトについて知る術がない。あなたが
new
JVMは新しいオブジェクトのコピーをインスタンス化し、それをそのままあなたに渡しますが、それは設定プロセスを経ることはありません。ビーンを構成する方法は3つあります。
Spring Boot を使って起動するこのコードは、すべて
このGitHubのプロジェクト
各アプローチの完全な実行プロジェクトを見れば、それを動作させるために必要なすべてを確認できます。
タグに
NullPointerException
:
nonworking
ビーンを注入する
最も望ましいのは、Springにすべてのビーンを自動配線させることです。これは最小限のコードしか必要とせず、最も保守性が高い方法です。自動配線が思い通りに動作するようにするために
MileageFeeCalculator
このように
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
異なるリクエストに対してサービスオブジェクトの新しいインスタンスを作成する必要がある場合にも、 インジェクションを使用することができます。 Spring Beanのスコープ .
を注入することで動作するタグです。
@MileageFeeCalculator
サービスオブジェクトを使用します。
working-inject-bean
コンフィギュラブルを使用する
で作成されたオブジェクトがどうしても必要な場合は
new
を自動配線にするには
は、Springの
@Configurable
アノテーションと AspectJ のコンパイル時のウィービング
を使用してオブジェクトをインジェクトします。この方法では、オブジェクトのコンストラクタにコードを挿入して、オブジェクトが作成されることをSpringに通知し、Springが新しいインスタンスを設定できるようにします。これはビルドの際に少し設定する必要があります(例えば
ajc
) とSpringの実行時設定ハンドラ (
@EnableSpringConfigured
をJavaConfigの構文で)。この方法は、Roo Active Recordシステムで使われている
new
のインスタンスに必要な永続性情報を注入することができます。
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
を使うことで機能するタグ
@Configurable
をサービスオブジェクトに追加します。
working-configurable
手動によるビーン検索:推奨しません
この方法は、特殊な状況下でレガシーコードとのインターフェイスにのみ適しています。Springが自動配線し、レガシーコードが呼び出せるシングルトンアダプタクラスを作成することがほぼ常に望ましいですが、Springアプリケーションコンテキストに直接Beanを要求することも可能です。
これを行うには、Springが参照を与えることのできるクラスが必要で、そのクラスは
ApplicationContext
オブジェクトを作成します。
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
そして、レガシーコードは
getContext()
を作成し、必要なビーンを取得します。
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}
Springコンテキストでサービスオブジェクトを手動で探すことで動作するタグ。
working-manual-lookup
関連
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException: 1
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
[解決済み] この2回(1927年)を引き算すると、なぜおかしな結果になるのでしょうか?
-
[解決済み] なぜパスワードにはStringではなくchar[]が好まれるのですか?
-
[解決済み] JavaScriptで空文字列/未定義文字列/null文字列をチェックするにはどうすればよいですか?
-
[解決済み] serialVersionUIDとは何ですか、またなぜそれを使用する必要がありますか?
-
[解決済み] JavaScriptでNULL、未定義、空白の変数をチェックする標準的な関数はありますか?
-
[解決済み] 変数が「未定義」または「NULL」であるかどうかを判断するにはどうすればよいですか?
-
[解決済み] instanceofを呼び出す前にnullチェックは必要ですか?
-
[解決済み】なぜJavaの+=, -=, *=, /=複合代入演算子はキャスティングを必要としないのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
スタイルシートとして解釈されるリソースが、MIMEタイプtext/htmlで転送される。
-
Eclipseで "XXXX "の解決策を(型に)解決することができない
-
Intellij IDEAのエラー「CreateProcess error=2, system could not find specified file」に対する完璧な解決策です。
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 4 at text.Division.main(Divisi
-
Spring BootのテストメソッドFailed to load ApplicationContextの問題を解決する
-
マスキング このリソースにアクセスするには、完全な認証が必要です。
-
SocketTimeoutExceptionです。読み込みがタイムアウトしました
-
起動時にEclipseエラーが発生しました。起動中に内部エラーが発生しました。java.lang.NullPoin: "Javaツーリングの初期化 "中に内部エラーが発生しました。
-
Java(1)仕上げの基本概念+eclipseのインストール構成
-
テストが見つかりませんでした