注:これは、一般的な問題に対する標準的な回答となることを目的としています。
フィールド@Service
(MileageFeeCalculator
)を持つSpringクラス()があり@Autowired
ますrateService
が、フィールドはnull
それを使おうとしたときのものです。ログには、MileageFeeCalculator
BeanとMileageRateService
Beanの両方が作成されていることが示されていますが、サービスBeanでメソッド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
}
}
自動配線する必要があるサービスBeanです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 Inversion of Control(IoC)コンテナーには、3つの主要な論理コンポーネントApplicationContext
があります。アプリケーションで使用できるコンポーネント(Bean)のレジストリ(と呼ばれる)、オブジェクトの依存関係を照合することによってオブジェクトの依存関係を挿入するコンフィギュレーターシステムです。コンテキスト内のBeanとの依存関係、および多くの異なるBeanの構成を調べて、それらを必要な順序でインスタンス化および構成する方法を決定できる依存関係ソルバー。
IoCコンテナは魔法ではなく、Javaオブジェクトについて何らかの方法で通知しない限り、Javaオブジェクトについて知る方法はありません。を呼び出すnew
と、JVMは新しいオブジェクトのコピーをインスタンス化し、それを直接ユーザーに渡します。構成プロセスを経ることはありません。Beanを構成する方法は3つあります。
このGitHubプロジェクトで、Spring Bootを使用して起動し、このコードをすべて投稿しました。各アプローチの完全に実行されているプロジェクトを見て、それを機能させるために必要なすべてを確認できます。:でタグ付けし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);
}
}
さまざまなリクエストに対してサービスオブジェクトの新しいインスタンスを作成する必要がある場合でも、SpringBeanスコープを使用してインジェクションを使用できます。
@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()
、必要な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
Webアプリケーションをコーディングしていない場合は、@ Autowiringが実行されるクラスがSpringBeanであることを確認してください。通常、Springコンテナは、SpringBeanと見なされる可能性のあるクラスを認識しません。SpringクラスについてSpringコンテナに通知する必要があります。
これは、appln-contxtで構成するか、クラスに@Componentとしてアノテーションを付けることで実現できます。また、new演算子を使用してアノテーション付きクラスを作成しないでください。以下のように、Appln-contextから取得してください。
@Component
public class MyDemo {
@Autowired
private MyService myService;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("test");
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
System.out.println("ctx>>"+ctx);
Customer c1=null;
MyDemo myDemo=ctx.getBean(MyDemo.class);
System.out.println(myDemo);
myDemo.callService(ctx);
}
public void callService(ApplicationContext ctx) {
// TODO Auto-generated method stub
System.out.println("---callService---");
System.out.println(myService);
myService.callMydao();
}
}
実際には、JVM管理対象オブジェクトまたはSpring管理対象オブジェクトのいずれかを使用してメソッドを呼び出す必要があります。コントローラクラスの上記のコードから、自動配線されたオブジェクトを持つサービスクラスを呼び出すための新しいオブジェクトを作成しています。
MileageFeeCalculator calc = new MileageFeeCalculator();
そのため、そのようには機能しません。
このソリューションは、このMileageFeeCalculatorをコントローラー自体の自動配線オブジェクトとして作成します。
次のようにControllerクラスを変更します。
@Controller
public class MileageFeeController {
@Autowired
MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
IoCの世界での生活にあまり慣れていなかったときに、同じ問題に遭遇したことがあります。@Autowired
私のBeanの1つのフィールドは、実行時にnullです。
根本的な原因は、Spring IoCコンテナーによって維持される自動作成されたBean(@Autowired
フィールドが実際に適切に注入されている)を使用する代わりにnew
、そのBeanタイプの独自のインスタンスを使用して使用していることです。もちろん@Autowired
、Springには注入する機会がないため、このフィールドはnullです。
あなたの問題は新しいです(Javaスタイルでのオブジェクト作成)
MileageFeeCalculator calc = new MileageFeeCalculator();
アノテーションを使用する@Service
と@Component
、
サーバーの起動時にSpring@Configuration
の
アプリケーションコンテキストでBeanが作成されます。ただし、new演算子を使用してオブジェクトを作成すると、そのオブジェクトは、すでに作成されているアプリケーションコンテキストに登録されません。たとえば、私が使用したEmployee.javaクラス。
これをチェックしてください:
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String name = "tenant";
System.out.println("Bean factory post processor is initialized");
beanFactory.registerScope("employee", new Employee());
Assert.state(beanFactory instanceof BeanDefinitionRegistry,
"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (name.equals(definition.getScope())) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
}
}
}
}
私はSpringを初めて使用しますが、この実用的なソリューションを発見しました。それが非難できる方法かどうか教えてください。
私applicationContext
はこのBeanにSpringを注入させます:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils {
public static ApplicationContext ctx;
/**
* Make Spring inject the application context
* and save it on a static variable,
* so that it can be accessed from any point in the application.
*/
@Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
必要に応じて、このコードをメインアプリケーションクラスにも配置できます。
他のクラスは次のように使用できます。
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
このようにして、任意のBeanは、アプリケーション内の任意のオブジェクト(これもでインスタンス化されますnew
)によって静的な方法で取得できます。
まれなケースのようですが、これが私に起こったことです:
@Inject
代わりに@Autowired
、Springでサポートされているjavaee標準を使用しました。1つの場所ではなく、すべての場所で正常に機能し、Beanが正しく注入されました。豆の注入は同じようです
@Inject
Calculator myCalculator
ついに、エラーはcom.opensymphony.xwork2.Inject
、javax.inject.Inject
!の代わりにインポートした(実際にはEclipseオートコンプリート機能)というものであることがわかりました。
だから、要約必ずあなたの注釈ことを確認する(@Autowired
、@Inject
、@Service
、...)正しいパッケージを持っています!
これがテストクラスで発生している場合は、クラスに注釈を付けることを忘れていないことを確認してください。
たとえば、Spring Bootの場合:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
....
SpringBootは進化し続けています。@RunWith
正しいバージョンのJUnitを使用すれば、使用する必要はなくなりました。
以下のために@SpringBootTest
仕事に一人で立って、あなたが使用する必要がある@Test
からJava JUnit5アノテーションの違い。
//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5
@SpringBootTest
public class MyTests {
....
この構成を間違えると、テストはコンパイルされますが@Autowired
、@Value
フィールド(たとえば)はになりますnull
。Spring Bootは魔法のように動作するため、この障害を直接デバッグする方法がほとんどない場合があります。
アノテーション付きのクラスをスキャンするようにSpringに指示しなかったと思います。
Spring@ComponentScan("packageToScan")
アプリケーションの構成クラスで使用して、Springにスキャンを指示できます。
@Service, @Component
などの注釈はメタ記述を追加します。
Springは、Beanとして作成されたか、アノテーションでマークされたクラスのインスタンスのみを注入します。
注釈が付けられたクラスは、注入する前に春によって識別される必要があります@ComponentScan
。注釈が付けられたクラスを春に探すように指示します。Springが検出@Autowired
すると、関連するBeanを検索し、必要なインスタンスを注入します。
アノテーションのみを追加し、依存性注入を修正または促進しません。Springはどこを探すべきかを知る必要があります。
別の解決策は、次のように呼び出し
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
を行うことです。MileageFeeCalculatorコンストラクターへ:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- will be autowired when constructor is called
public MileageFeeCalculator() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
更新:本当に賢い人々は、この答えをすぐに指摘しました。これは、以下に説明する奇妙さを説明しています。
元の回答:
それが誰かに役立つかどうかはわかりませんが、一見正しいことをしている間でも同じ問題に悩まされていました。Mainメソッドには、次のようなコードがあります。
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
そしてtoken.xml
ファイルに私は行を持っていました
<context:component-scan base-package="package.path"/>
package.pathがもう存在しないことに気づいたので、行を完全に削除しました。
そしてその後、NPEが入り始めました。pep-config.xml
私はたった2つの豆を持っていました:
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
そしてSomeAbacクラスには次のように宣言されたプロパティがあります
@Autowired private Settings settings;
何らかの理由で、要素がまったく存在しない場合、init()の設定はnull<context:component-scan/>
ですが、要素が存在し、basePackageとしていくつかのbsがある場合、すべてが正常に機能します。この行は次のようになります。
<context:component-scan base-package="some.shit"/>
そしてそれは動作します。誰かが説明を提供できるかもしれませんが、私にとっては今はそれで十分です)
これは、MileageFeeCalculator calc = new MileageFeeCalculator();
私たちがSpringを使用しているNullPointerExceptionを与える原因です-オブジェクトを手動で作成する必要はありません。オブジェクトの作成はIoCコンテナによって処理されます。
この問題は、サービスクラスで@Serviceアノテーションを使用し、必要なBeanクラスAをパラメーターとして他のBeanクラスBコンストラクターに渡し、クラスBのコンストラクターに@Autowiredアノテーションを付けることで修正することもできます。ここにサンプルスニペット:
@Service
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void useClassAObjectHere(){
classA.callMethodOnObjectA();
}
}
簡単に言えば、@Autowired
フィールドが存在する主な理由は2つあります。null
あなたのクラスは春の豆ではありません。
フィールドは豆ではありません。
ここで言及されていないことは、この記事の「実行順序」の段落で説明されています。
クラスに@Componentまたは派生物@Serviceまたは@Repository(もっとあると思います)で注釈を付ける必要があることを「学習」した後、それらの内部の他のコンポーネントを自動配線するために、これらの他のコンポーネントがコンストラクター内でまだnullであることに気付きました親コンポーネントの。
@PostConstructを使用すると、次のことが解決されます。
@SpringBootApplication
public class Application {
@Autowired MyComponent comp;
}
そして:
@Component
public class MyComponent {
@Autowired ComponentDAO dao;
public MyComponent() {
// dao is null here
}
@PostConstruct
public void init() {
// dao is initialized here
}
}
これは、ユニットテストの場合にのみ有効です。
私のサービスクラスにはサービスのアノテーションがあり、それは@autowired
別のコンポーネントクラスでした。私がテストしたとき、コンポーネントクラスはnullになりました。サービスクラスの場合、を使用してオブジェクトを作成していたためnew
単体テストを作成している場合は、を使用してオブジェクトを作成していないことを確認してくださいnew object()
。代わりにinjectMockを使用してください。
これで私の問題は修正されました。ここに便利なリンクがあります
また、何らかの理由で@Service
asfinal
でメソッドを作成した場合、そこからアクセスする自動配線されたBeanは常にになりますnull
。
質問に完全に関連しているわけではありませんが、フィールドインジェクションがnullの場合でも、コンストラクターベースのインジェクションは正常に機能します。
private OrderingClient orderingClient;
private Sales2Client sales2Client;
private Settings2Client settings2Client;
@Autowired
public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
this.orderingClient = orderingClient;
this.sales2Client = sales2Client;
this.settings2Client = settings2Client;
}
以下のいずれかが機能します:
@Autowiredを使用しているクラスはBeanではありません(確かにどこかでnew()を使用した可能性があります)。
SpringConfigクラス内では、Springが@Componentを検索する必要のあるパッケージについて言及していません(@ComponentScan(basePackages "here")について話しています)
上記の2つが機能しない場合は、System.out.println()の配置を開始し、どこで問題が発生しているかを把握します。
特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。
ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。
ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。
画像クレジット:Richard Mackney / Flickrトラベリングライトは必需品だけを運ぶことを意味するかもしれませんが、デバイスを補充する方法がない外出先では、接続を維持するのが難しくなる可能性があります。それはあなたがすべての生き物の快適さやクールなガジェットを捨てる必要があるという意味ではありません、ただあなたがいくつかのより小さなものを手に入れる必要があるということです、そしておそらくあなた自身をジュースに保つためにいくつかの、例えば非正統的な充電装置を使うでしょう。
ニューヨーク州スプリンググレンにある放棄されたホモワックロッジのボーリング場。キャッツキル南部のこの地域は、ニューヨーク市からのユダヤ人の行楽客に人気があることから、かつてはボルシチベルトとして知られていました。
ブルックリンスレートブルックリンスレートのマグカップとコースターの賞賛をすでに歌っており、それらの食器製品も同様に堅実です。ブルックリンスレートは、さまざまなサイズとテクスチャのスレートの完全な採石場を販売しています。一部のオプションは赤でも利用できます。上で見ることができるように、彼らは同様にカスタマイズをします。
画像:Juan Gaertner / Shutterstock私たちの体の内部は、私たちの細胞とは何の関係もない何十億もの微生物が住んでいる本物の生態系です。これがまだ少し気になることではなかったかのように、これらの微生物の99%が研究されたことがないことがわかりました。
Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday
シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。
オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。
Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。
遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。
2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。
計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。