注: これは、一般的な問題に対する標準的な回答となることを目的としています。
フィールド( ) を持つSpring@Service
クラス( ) がありますが、使用しようとするとフィールド が表示されます。ログには、 Bean とBean の両方が作成されていることが示されていますが、サービス Bean で メソッドを呼び出そうとすると、が表示されます。Spring がフィールドを自動配線しないのはなぜですか?MileageFeeCalculator
@Autowired
rateService
null
MileageFeeCalculator
MileageRateService
NullPointerException
mileageCharge
コントローラークラス:
@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
が、そうではないサービス Bean:
@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)
...
ベストアンサー1
フィールドに注釈が付けられているのは、Spring が、作成したのコピーを認識しておらず、それを自動接続することも知らなかったため@Autowired
です。null
MileageFeeCalculator
new
Spring の制御反転 (IoC) コンテナには、アプリケーションで使用できるコンポーネント (Bean) のレジストリ ( と呼ばれるApplicationContext
)、コンテキスト内の Bean と依存関係を一致させることによってオブジェクトの依存関係を注入するコンフィギュラ システム、およびさまざまな Bean の構成を調べて、それらを必要な順序でインスタンス化および構成する方法を決定できる依存関係ソルバという 3 つの主要な論理コンポーネントがあります。
IoC コンテナは魔法ではありません。何らかの方法で Java オブジェクトを通知しない限り、Java オブジェクトについて知る方法はありません。 を呼び出すとnew
、JVM は新しいオブジェクトのコピーをインスタンス化し、それを直接渡します。構成プロセスを経ることはありません。Bean を構成する方法は 3 つあります。
このコードはすべてSpring Bootを使用して起動し、このGitHubプロジェクト; 各アプローチの完全な実行中のプロジェクトを見て、それを機能させるために必要なすべてのものを確認できます。次のタグを付けますNullPointerException
:nonworking
豆を注入する
最も望ましいオプションは、Spring ですべての Bean を自動配線することです。これにより、必要なコードの量が最も少なくなり、メンテナンス性も最も高くなります。自動配線を希望どおりに動作させるには、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
@Configurableを使用する
で作成されたオブジェクト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
手動Bean検索: 非推奨
このアプローチは、特別な状況でレガシー コードとインターフェイスする場合にのみ適しています。ほとんどの場合、Spring が自動接続し、レガシー コードが呼び出すことができるシングルトン アダプター クラスを作成することが望ましいですが、Bean を Spring アプリケーション コンテキストに直接要求することも可能です。
これを行うには、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()
必要な Bean を呼び出して取得できます。
@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