Warum ist mein Spring @ Autowired-Feld null?

608

Hinweis: Dies soll eine kanonische Antwort auf ein häufiges Problem sein.

Ich habe eine Spring- @ServiceKlasse ( MileageFeeCalculator) mit einem @AutowiredFeld ( rateService), aber das Feld ist, nullwenn ich versuche, es zu verwenden. Die Protokolle zeigen, dass sowohl die MileageFeeCalculatorBean als auch die MileageRateServiceBean erstellt werden, aber ich erhalte eine, NullPointerExceptionwenn ich versuche, die mileageChargeMethode für meine Service-Bean aufzurufen . Warum verdrahtet 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);
    }
}

Serviceklasse:

@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
    }
}

Service Bean, die automatisch verdrahtet werden sollte, MileageFeeCalculatoraber nicht:

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

Wenn ich es versuche GET /mileage/3, erhalte ich folgende 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)
    ...
chrylis -vorsichtig optimistisch-
quelle
3
Ein anderes Szenario kann sein, wenn Bean Fim Konstruktor einer anderen Bean aufgerufen wird S. In diesem Fall übergeben Sie die erforderliche Bean Fals Parameter an den SKonstruktor der anderen Beans und kommentieren Sie den Konstruktor von Smit @Autowire. Denken Sie daran, die Klasse der ersten Bean Fmit zu kommentieren @Component.
Aliopi
Ich habe einige Beispiele, die diesem sehr ähnlich sind, mit Gradle hier codiert: github.com/swimorsink/spring-aspectj-examples . Hoffentlich findet es jemand nützlich.
Ross117

Antworten:

649

Das mit Anmerkungen versehene Feld @Autowiredist darauf zurückzuführen, nulldass Spring nichts über die Kopie weiß, mit der MileageFeeCalculatorSie erstellt haben, newund nicht wusste, dass sie automatisch verdrahtet werden soll.

Der IoC-Container (Spring Inversion of Control) besteht aus drei logischen Hauptkomponenten: einer Registrierung (der so genannten ApplicationContext) von Komponenten (Beans), die von der Anwendung verwendet werden können, und einem Konfigurationssystem, das die Abhängigkeiten von Objekten in sie einfügt, indem die Abhängigkeiten mit Beans im Kontext und ein Abhängigkeitslöser, der eine Konfiguration vieler verschiedener Beans anzeigen und bestimmen kann, wie diese in der erforderlichen Reihenfolge instanziiert und konfiguriert werden.

Der IoC-Container ist keine Zauberei und kann nur dann über Java-Objekte informiert werden, wenn Sie ihn irgendwie darüber informieren. Wenn Sie anrufen new, instanziiert die JVM eine Kopie des neuen Objekts und gibt sie direkt an Sie weiter - sie durchläuft nie den Konfigurationsprozess. Es gibt drei Möglichkeiten, wie Sie Ihre Beans konfigurieren können.

Ich habe den gesamten Code mit Spring Boot zum Starten in diesem GitHub-Projekt veröffentlicht . Sie können sich für jeden Ansatz ein vollständig laufendes Projekt ansehen, um alles zu sehen, was Sie benötigen, damit es funktioniert. Tag mit dem NullPointerException:nonworking

Injizieren Sie Ihre Bohnen

Am besten lassen Sie Spring alle Ihre Bohnen automatisch verdrahten. Dies erfordert die geringste Menge an Code und ist am wartbarsten. Damit die automatische Verdrahtung so funktioniert, wie Sie es möchten, gehen Sie MileageFeeCalculatorwie folgt vor :

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

Wenn Sie eine neue Instanz Ihres Serviceobjekts für verschiedene Anforderungen erstellen müssen, können Sie die Injektion weiterhin mithilfe der Spring Bean-Bereiche verwenden .

Tag, das durch Injizieren des @MileageFeeCalculatorServiceobjekts funktioniert :working-inject-bean

Verwenden Sie @Configurable

Wenn Sie wirklich Objekte benötigen, die mit erstellt wurden new, um automatisch verdrahtet zu werden, können Sie die Spring- @ConfigurableAnnotation zusammen mit AspectJ-Weben zur Kompilierungszeit verwenden , um Ihre Objekte zu injizieren. Dieser Ansatz fügt Code in den Konstruktor Ihres Objekts ein, der Spring darüber informiert, dass er erstellt wird, damit Spring die neue Instanz konfigurieren kann. Dies erfordert ein wenig Konfiguration in Ihrem Build (z. B. Kompilieren mit ajc) und @EnableSpringConfiguredAktivieren der Spring-Laufzeitkonfigurationshandler ( mit der JavaConfig-Syntax). Dieser Ansatz wird vom Roo Active Record-System verwendet, damit newInstanzen Ihrer Entitäten die erforderlichen Persistenzinformationen einspeisen können.

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

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

Tag, das @Configurablefür das Serviceobjekt verwendet wird:working-configurable

Manuelle Bohnensuche: nicht empfohlen

Dieser Ansatz eignet sich nur für die Schnittstelle mit Legacy-Code in besonderen Situationen. Es ist fast immer vorzuziehen, eine Singleton-Adapterklasse zu erstellen, die Spring automatisch verdrahten und den Legacy-Code aufrufen kann. Es ist jedoch möglich, den Spring-Anwendungskontext direkt nach einer Bean zu fragen.

Dazu benötigen Sie eine Klasse, auf die Spring einen Verweis auf das ApplicationContextObjekt geben kann:

@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;
    }
}

Dann kann Ihr Legacy-Code getContext()die benötigten Beans aufrufen und abrufen:

@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);
    }
}

Tag, das funktioniert, indem das Serviceobjekt im Spring-Kontext manuell nachgeschlagen wird: working-manual-lookup

chrylis -vorsichtig optimistisch-
quelle
1
Die andere zu betrachtende Sache ist das Erstellen von Objekten für Beans in einer @ConfigurationBean, wobei die Methode zum Erstellen einer Instanz einer bestimmten Bean-Klasse mit Anmerkungen versehen ist @Bean.
Donal Fellows
@DonalFellows Ich bin mir nicht ganz sicher, wovon du sprichst ("machen" ist mehrdeutig). Sprechen Sie über ein Problem mit mehreren @BeanMethodenaufrufen bei Verwendung von Spring Proxy AOP?
Chrylis
1
Hallo, ich stoße auf ein ähnliches Problem. Wenn ich jedoch Ihren ersten Vorschlag verwende, denkt meine Anwendung, dass "calc" beim Aufrufen der "mileageFee" -Methode null ist. Es ist, als würde es das nie initialisieren @Autowired MileageFeeCalculator calc. Irgendwelche Gedanken?
Theo
Ich denke, Sie sollten oben in Ihrer Antwort einen Eintrag hinzufügen, der erklärt, dass das Abrufen der ersten Bean, der Wurzel, von der aus Sie alles tun, über das erfolgen sollte ApplicationContext. Einige Benutzer (für die ich als Duplikate geschlossen habe) verstehen dies nicht.
Sotirios Delimanolis
@SotiriosDelimanolis Bitte erläutern Sie das Problem. Ich bin mir nicht sicher, welchen Punkt du machst.
Chrylis
59

Wenn Sie keine Webanwendung codieren, stellen Sie sicher, dass Ihre Klasse, in der @Autowiring ausgeführt wird, eine Spring Bean ist. Normalerweise kennt der Frühlingsbehälter die Klasse nicht, die wir als Frühlingsbohne betrachten könnten. Wir müssen dem Frühlingscontainer von unseren Frühlingsklassen erzählen.

Dies kann durch Konfigurieren in appln-contxt erreicht werden. Besser ist es, die Klasse als @Component zu kommentieren und die kommentierte Klasse nicht mit dem neuen Operator zu erstellen. Stellen Sie sicher, dass Sie es aus dem Appln-Kontext wie unten erhalten.

@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();

    }

}
Shirish Coolkarni
quelle
Hallo, ich habe deine Lösung durchgearbeitet, das ist richtig. Und hier möchte ich wissen: "Warum wir keine Instanz einer kommentierten Klasse mit einem neuen Operator erstellen, darf ich den Grund dafür kennen.
Ashish
3
Wenn Sie das Objekt mit new erstellen, behandeln Sie den Lebenszyklus der Bean, der dem Konzept des IOC widerspricht. Wir müssen den Container bitten, es zu tun, was es besser macht
Shirish Coolkarni
41

Eigentlich sollten Sie entweder JVM-verwaltete Objekte oder Spring-verwaltete Objekte verwenden, um Methoden aufzurufen. Aus dem obigen Code in Ihrer Controller-Klasse erstellen Sie ein neues Objekt zum Aufrufen Ihrer Serviceklasse mit einem automatisch verdrahteten Objekt.

MileageFeeCalculator calc = new MileageFeeCalculator();

so wird es nicht so funktionieren.

Die Lösung macht diesen MileageFeeCalculator zu einem automatisch verdrahteten Objekt im Controller selbst.

Ändern Sie Ihre Controller-Klasse wie unten.

@Controller
public class MileageFeeController {

    @Autowired
    MileageFeeCalculator calc;  

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}
Ravi Durairaj
quelle
4
Das ist die Antwort. Da Sie einen neuen MilageFeeCalculator selbst instanziieren, ist Spring nicht an der Instanziierung beteiligt, sodass Spring Spring nicht weiß, dass das Objekt vorhanden ist. Daher kann es nichts dagegen tun, wie Abhängigkeiten zu injizieren.
Robert Greathouse
26

Ich bin einmal auf das gleiche Problem gestoßen, als ich nicht ganz daran gewöhnt war the life in the IoC world. Das @AutowiredFeld einer meiner Beans ist zur Laufzeit null.

Die Hauptursache ist, dass ich anstelle der automatisch erstellten Bean, die vom Spring IoC-Container verwaltet wird (dessen @AutowiredFeld indeedordnungsgemäß eingefügt wurde), newingmeine eigene Instanz dieses Bean-Typs bin und sie verwende. Natürlich ist dieses @AutowiredFeld null, weil Spring keine Chance hat, es zu injizieren.

smwikipedia
quelle
22

Ihr Problem ist neu (Objekterstellung im Java-Stil)

MileageFeeCalculator calc = new MileageFeeCalculator();

Mit Anmerkung @Service, @Component, @ConfigurationBohnen werden in dem erstellten
Anwendungskontext des Frühlings , wenn der Server gestartet wird. Wenn wir jedoch Objekte mit einem neuen Operator erstellen, wird das Objekt nicht im bereits erstellten Anwendungskontext registriert. Zum Beispiel habe ich die Employee.java-Klasse verwendet.

Überprüfen Sie dies heraus:

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());
        }
    }
}

}
Deepak
quelle
12

Ich bin neu in Spring, aber ich habe diese funktionierende Lösung entdeckt. Bitte sagen Sie mir, ob es ein abwertbarer Weg ist.

Ich lasse Spring applicationContextin diese Bohne spritzen :

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;       
    }
}

Sie können diesen Code auch in die Hauptanwendungsklasse einfügen, wenn Sie möchten.

Andere Klassen können es so verwenden:

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

Auf diese Weise kann jede Bohne von jedem Objekt in der Anwendung (auch beabsichtigt new) und auf statische Weise erhalten werden .

bläulich
quelle
1
Dieses Muster ist erforderlich, um Spring Beans für Legacy-Code zugänglich zu machen, sollte jedoch in neuem Code vermieden werden.
Chrylis
2
Du bist nicht neu im Frühling. Du bist ein Profi. :)
sapy
Du hast mich gerettet ...
Govind Singh
In meinem Fall habe ich dies benötigt, weil es nur wenige Klassen von Drittanbietern gab. Spring (IOC) hatte keine Kontrolle über sie. Diese Klassen wurden nie von meiner Spring Boot App aufgerufen. Ich folgte diesem Ansatz und es funktionierte für mich.
Joginder Malik
12

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

Wir haben @Injectstattdessen @Autowiredden von Spring unterstützten Javaee-Standard verwendet. An allen Stellen funktionierte es gut und die Bohnen wurden richtig injiziert, anstatt an einer Stelle. Die Bohneninjektion scheint gleich zu sein

@Inject
Calculator myCalculator

Endlich stellten wir fest, dass der Fehler darin bestand, dass wir (eigentlich die Eclipse-Funktion zur automatischen Vervollständigung) com.opensymphony.xwork2.Injectanstelle von importiert haben javax.inject.Inject!

Um es zusammenzufassen, stellen Sie sicher , dass Ihre Anmerkungen ( @Autowired, @Inject, @Service, ...) richtig Pakete haben!

Alireza Fattahi
quelle
5

Ich denke, Sie haben es versäumt, spring anzuweisen, Klassen mit Anmerkungen zu scannen.

Sie können @ComponentScan("packageToScan")die Konfigurationsklasse Ihrer Federanwendung verwenden, um die Feder zum Scannen anzuweisen.

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

Spring fügt nur Instanzen dieser Klassen ein, die entweder als Bean erstellt oder mit Anmerkungen markiert sind.

Mit Anmerkungen gekennzeichnete Klassen müssen vor dem Einspritzen durch die Feder identifiziert werden. Weisen Sie die @ComponentScanFeder an, nach den mit Anmerkungen gekennzeichneten Klassen zu suchen. Wenn Spring es findet @Autowired, sucht es nach der zugehörigen Bean und injiziert die erforderliche Instanz.

Wenn Sie nur Anmerkungen hinzufügen, die Abhängigkeitsinjektion nicht korrigieren oder erleichtern, muss Spring wissen, wo Sie suchen müssen.

msucil
quelle
stieß darauf, als ich vergaß, <context:component-scan base-package="com.mypackage"/>zu meiner beans.xmlDatei hinzuzufügen
Ralph Callaway
5

Wenn dies in einer Testklasse geschieht, stellen Sie sicher, dass Sie nicht vergessen haben, die Klasse mit Anmerkungen zu versehen.

Zum Beispiel in Spring Boot :

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

Es vergeht einige Zeit ...

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

Für @SpringBootTestallein zur Arbeit stehen, müssen Sie die Verwendung @Testvon JUnit5 statt JUnit4 .

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

@SpringBootTest
public class MyTests {
    ....

Wenn Sie diese Konfiguration falsch verstehen, werden Ihre Tests kompiliert, aber @Autowiredund @ValueFelder (zum Beispiel) werden null. Da Spring Boot magisch arbeitet, haben Sie möglicherweise nur wenige Möglichkeiten, diesen Fehler direkt zu beheben.

kein Balken
quelle
Hinweis: @ValueWird bei Verwendung mit staticFeldern null sein .
Nobar
Spring bietet zahlreiche Möglichkeiten zum Fehlschlagen (ohne Hilfe des Compilers). Wenn etwas schief geht, kehren Sie am besten zum ersten Punkt zurück - und verwenden nur die Kombination von Anmerkungen, von denen Sie wissen, dass sie zusammenarbeiten.
Nobar
4

Eine andere Lösung wäre ein Aufruf: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
Zum MileageFeeCalculator-Konstruktor wie folgt:

@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()); 
    }
}
Ondrej Bozek
quelle
Dies verwendet eine unsichere Veröffentlichung.
Chrylis
3

UPDATE: Wirklich kluge Leute haben schnell auf diese Antwort hingewiesen, was die unten beschriebene Verrücktheit erklärt

URSPRÜNGLICHE ANTWORT:

Ich weiß nicht, ob es jemandem hilft, aber ich hatte das gleiche Problem, auch wenn ich Dinge scheinbar richtig gemacht habe. In meiner Hauptmethode 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.xmlDatei hatte ich eine Zeile

<context:component-scan base-package="package.path"/>

Ich habe festgestellt, dass der package.path nicht mehr vorhanden ist, daher habe ich die Zeile endgültig gelöscht.

Und danach kam NPE herein. In einem hatte pep-config.xmlich nur 2 Bohnen:

<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>

und SomeAbac-Klasse hat eine Eigenschaft deklariert als

@Autowired private Settings settings;

Aus einem unbekannten Grund sind die Einstellungen in init () null , wenn das <context:component-scan/>Element überhaupt nicht vorhanden ist, aber wenn es vorhanden ist und einige bs als Basispaket enthält, funktioniert alles gut. Diese Zeile sieht jetzt so aus:

<context:component-scan base-package="some.shit"/>

und es funktioniert. Vielleicht kann jemand eine Erklärung liefern, aber für mich ist es gerade genug)

62mkv
quelle
5
Diese Antwort ist die Erklärung. <context:component-scan/>impliziert implizit <context:annotation-config/>notwendig, damit das @Autowiredfunktioniert.
ForNeVeR
3

Dies ist der Schuldige für die NullPointerException. MileageFeeCalculator calc = new MileageFeeCalculator();Wir verwenden Spring - müssen das Objekt nicht manuell erstellen. Die Objekterstellung wird vom IoC-Container übernommen.

Atul Jain
quelle
2

Sie können dieses Problem auch beheben, indem Sie die Annotation @Service für die Serviceklasse verwenden und die erforderliche Bean classA als Parameter an den Konstruktor der anderen Beans classB übergeben und den Konstruktor der Klasse B mit @Autowired kommentieren. Beispielausschnitt hier:

@Service
public class ClassB {

    private ClassA classA;

    @Autowired
    public ClassB(ClassA classA) {
        this.classA = classA;
    }

    public void useClassAObjectHere(){
        classA.callMethodOnObjectA();
    }
}
Abhishek
quelle
Das hat bei mir funktioniert, aber können Sie bitte näher erläutern, wie das Problem dadurch gelöst wird?
CruelEngine
1
@CruelEngine, sehen Sie, dies ist die Konstruktorinjektion (bei der Sie explizit ein Objekt festlegen), anstatt nur die Feldinjektion zu verwenden (dies geschieht meistens durch die Federkonfiguration). Wenn Sie also ein Objekt der Klasse B mit dem Operator "new" erstellen, ist dies ein anderer Bereich, der für ClassA nicht sichtbar oder automatisch verdrahtet ist. Daher würde beim Aufrufen von classB.useClassAObjectHere () NPE ausgelöst, da das classA-Objekt nicht automatisch verdrahtet wurde, wenn Sie nur das Feld Injection deklarieren. Lesen chrylis versucht das gleiche zu erklären. Aus diesem Grund wird eine Konstruktorinjektion gegenüber einer Feldinjektion empfohlen. Macht es jetzt Sinn?
Abhishek
1

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 denke, es gibt noch mehr) mit Anmerkungen versehen musste, um andere Komponenten in ihnen automatisch zu verdrahten, fiel mir auf, dass diese anderen Komponenten im Konstruktor immer noch null waren der übergeordneten Komponente.

Die Verwendung von @PostConstruct löst Folgendes:

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

und:

@Component
public class MyComponent {
    @Autowired ComponentDAO dao;

    public MyComponent() {
        // dao is null here
    }

    @PostConstruct
    public void init() {
        // dao is initialized here
    }
}
JackLeEmmerdeur
quelle
1

Dies gilt nur im Falle eines Unit-Tests.

Meine Service-Klasse hatte eine Annotation des Service und es war eine @autowiredandere Komponentenklasse. Beim Testen wurde die Komponentenklasse null. Weil ich für die Serviceklasse das Objekt mit erstellt habenew

Wenn Sie einen Komponententest schreiben, stellen Sie sicher, dass Sie kein Objekt mit erstellen new object(). Verwenden Sie stattdessen injizierenMock.

Dies hat mein Problem behoben. Hier ist ein nützlicher Link

Rishabh Agarwal
quelle
0

Beachten Sie auch, dass, wenn Sie aus irgendeinem Grund eine Methode in a @Serviceas finalerstellen, die automatisch verdrahteten Beans, auf die Sie von dort aus zugreifen, immer vorhanden sind null.

yglodt
quelle
0

In einfachen Worten gibt es hauptsächlich zwei Gründe für ein @AutowiredFeldnull

  • IHRE KLASSE IST KEINE FRÜHLINGSBOHNE.

  • Das Feld ist keine Biene.

samuelj90
quelle
0

Nicht vollständig mit der Frage verbunden, aber wenn die Feldinjektion null ist, funktioniert die konstruktorbasierte Injektion immer noch einwandfrei.

    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;
    }
Chaklader Asfak Arefe
quelle