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

9voto

SAMUEL Punkte 7352

In einfachen Worten gibt es hauptsächlich zwei Gründe für ein @Autowired Feld, das null ist

  • Ihre KLASSE IST KEIN SPRING BEAN.

Die Klasse, in der Sie die @Autowire-Annotation definieren, ist kein Spring Bean. Daher verdrahtet Spring die Member nicht automatisch.

  • DAS FELD IST KEIN BEAN.

Es gibt keinen Bean mit dem Typ oder Typ in der Hierarchie, den Sie im @Autowired-Feld angegeben haben, der noch nicht im Spring-Anwendungskontext oder Register vorhanden ist

8voto

Ondrej Bozek Punkte 10256

Eine andere Lösung wäre, einen Aufruf von SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
im Konstruktor von MileageFeeCalculator wie folgt zu platzieren:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- wird autowired, wenn der Konstruktor aufgerufen wird

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}

6voto

msucil Punkte 786

Ich denke, du hast vergessen, Spring anzuweisen, Klassen mit Annotationen zu scannen.

Du kannst @ComponentScan("PaketZumScannen") auf der Konfigurationsklasse deiner Spring-Anwendung verwenden, um Spring anzuweisen zu scannen.

@Service, @Component usw. Annotationen fügen Meta-Beschreibung hinzu.

Spring injectet nur Instanzen von Klassen, die entweder als Bean erstellt oder mit Annotation markiert sind.

Klassen, die mit Annotation markiert sind, müssen von Spring identifiziert werden, bevor sie injiziert werden. @ComponentScan weist Spring an, nach den mit Annotation markierten Klassen zu suchen. Wenn Spring @Autowired findet, sucht es nach der entsprechenden Bean und injiziert die benötigte Instanz.

Nur die Hinzufügung einer Annotation behebt oder erleichtert die Dependency Injection nicht, Spring muss wissen, wo es suchen soll.

5voto

Atul Jain Punkte 837

Dies ist der Übeltäter, der NullPointerException gibt MileageFeeCalculator calc = new MileageFeeCalculator(); Wir verwenden Spring - wir müssen kein Objekt manuell erstellen. Die Objekterstellung wird vom IoC-Container übernommen.

4voto

62mkv Punkte 1425

UPDATE: Wirklich kluge Leute haben schnell auf diese Antwort hingewiesen, die die unten beschriebene Seltsamkeit erklärt

URSPRÜNGLICHE ANTWORT:

Ich weiß nicht, ob es jemandem hilft, aber ich war auch bei scheinbar richtigen Handlungen mit dem gleichen Problem stecken geblieben. In meiner Main-Methode habe ich einen Code wie diesen:

ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);

und in einer token.xml Datei hatte ich eine Zeile

Ich habe festgestellt, dass das package.path nicht mehr existiert, also habe ich die Zeile einfach gestrichen.

Und danach begannen NPE zu erscheinen. In einer pep-config.xml hatte ich nur 2 Beans:

und die SomeAbac-Klasse hat eine Eigenschaft deklariert als

@Autowired private Settings settings;

aus irgendeinem unbekannten Grund ist settings in init() null, wenn das Element überhaupt nicht vorhanden ist, aber wenn es vorhanden ist und ein bs als basePackage hat, funktioniert alles gut. Diese Zeile sieht jetzt so aus:

und es funktioniert. Vielleicht kann jemand eine Erklärung liefern, aber für mich reicht es jetzt )

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