780 Stimmen

Warum ist mein Spring @Autowired-Feld null?

Hinweis: Dies soll eine kanonische Antwort für ein häufiges Problem sein.

Ich habe eine Spring @Service-Klasse (MileageFeeCalculator), die ein @Autowired-Feld (rateService) hat, aber das Feld ist null, wenn ich versuche, es zu verwenden. Die Protokolle zeigen, dass sowohl das MileageFeeCalculator-Bean als auch das MileageRateService-Bean erstellt werden, aber ich erhalte eine NullPointerException, wenn ich versuche, die Methode mileageCharge auf meinem Service-Bean aufzurufen. Warum verkabelt Spring das Feld nicht automatisch?

Controller-Klasse:

@Controller
public class MileageFeeController {
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = new MileageFeeCalculator();
        return calc.mileageCharge(miles);
    }
}

Service-Klasse:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- sollte autowired sein, ist null

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); // <--- wirft NPE
    }
}

Service-Bean, das in MileageFeeCalculator autowired werden sollte, aber nicht ist:

@Service
public class MileageRateService {
    public float ratePerMile() {
        return 0.565f;
    }
}

Wenn ich versuche, GET /mileage/3, erhalte ich diese Ausnahme:

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)
    ...

16voto

bluish Punkte 24479

Ich bin neu im Frühling, aber ich habe diese funktionierende Lösung entdeckt. Bitte sagen Sie mir, ob es eine veraltete Methode ist.

Ich lasse Spring applicationContext in diesem Bean injizieren:

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;

    /**
     * Lass Spring den Anwendungskontext injizieren
     * und speichere es in einer statischen Variable,
     * damit es von jedem Punkt in der Anwendung aus zugegriffen werden kann.
     */
    @Autowired
    private void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;       
    }
}

Sie können diesen Code auch in der Hauptanwendungsklasse platzieren, wenn Sie möchten.

Andere Klassen können es folgendermaßen verwenden:

MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);

Auf diese Weise kann jeder Bean von jedem Objekt in der Anwendung abgerufen werden (auch instanziiert mit new) und auf statische Weise.

15voto

Alireza Fattahi Punkte 37703

Es scheint ein seltener Fall zu sein, aber hier ist, was mir passiert ist:

Wir haben @Inject anstelle von @Autowired verwendet, was der von Spring unterstützte Java-EE-Standard ist. Überall hat es gut funktioniert und die Beans wurden korrekt injiziert, bis auf einen Ort. Die Bean-Injektion scheint identisch zu sein

@Inject
Calculator meinRechner

Zuletzt haben wir festgestellt, dass der Fehler darin bestand, dass wir (genauer gesagt, das Autovervollständigungs-Feature von Eclipse) com.opensymphony.xwork2.Inject anstelle von javax.inject.Inject importiert haben!

Also, um zusammenzufassen, stellen Sie sicher, dass Ihre Annotationen (@Autowired, @Inject, @Service, ...) die richtigen Pakete haben!

14voto

JackLeEmmerdeur Punkte 592

Was hier nicht erwähnt wurde, wird in diesem Artikel im Abschnitt "Ausführungsreihenfolge" beschrieben.

Nachdem ich "gelernt" hatte, dass ich eine Klasse mit @Component oder den Derivaten @Service oder @Repository (ich nehme an, es gibt noch mehr) annotieren musste, um andere Komponenten darin zu verdrahten, fiel mir auf, dass diese anderen Komponenten immer noch null waren im Konstruktor der übergeordneten Komponente.

Dieses Problem lässt sich mit @PostConstruct lösen:

@SpringBootApplication
public class Application {
    @Autowired MyComponent comp;
}

und:

@Component
public class MyComponent {
    @Autowired ComponentDAO dao;

    public MyComponent() {
        // dao ist hier null
    }

    @PostConstruct
    public void init() {
        // dao wird hier initialisiert
    }
}

12voto

Ashutosh Tiwari Punkte 1006

Eines der folgenden wird funktionieren:

  1. Die Klasse, in der Sie @Autowired verwenden, ist kein Bean (Sie haben irgendwo new() verwendet, da bin ich sicher).

  2. In der SpringConfig-Klasse haben Sie die Pakete nicht erwähnt, nach denen Spring suchen soll @Component (Ich spreche von @ComponentScan(basePackages"here"))

Wenn die obigen beiden nicht funktionieren...fangen Sie an, System.out.println() zu verwenden und finden Sie heraus, wo der Fehler liegt.

10voto

Brent Bradburn Punkte 45995

Wenn dies in einer Testklasse passiert, stellen Sie sicher, dass Sie die Klasse nicht vergessen haben zu kennzeichnen.

Zum Beispiel in Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
    ....

Es vergeht einige Zeit...

Spring Boot entwickelt sich weiter. Es ist nicht mehr erforderlich, @RunWith zu verwenden, wenn Sie die richtige Version von JUnit verwenden.

Damit @SpringBootTest eigenständig funktioniert, müssen Sie @Test von JUnit5 anstelle von JUnit4 verwenden.

//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5

@SpringBootTest
public class MyTests {
    ....

Wenn Sie diese Konfiguration falsch machen, werden Ihre Tests kompilieren, aber @Autowired und @Value Felder (zum Beispiel) werden null sein. Da Spring Boot durch Magie funktioniert, haben Sie möglicherweise nur wenige Möglichkeiten, dieses Versagen direkt zu debuggen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X