Feld konnte nicht automatisch verdrahtet werden: RestTemplate in Spring-Startanwendung

108

Beim Ausführen der Spring Boot-Anwendung während des Startvorgangs wird die folgende Ausnahme angezeigt:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.web.client.RestTemplate com.micro.test.controller.TestController.restTemplate; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.client.RestTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Ich verdrahtete RestTemplate automatisch in meinem TestController. Ich verwende Maven für das Abhängigkeitsmanagement.

TestMicroServiceApplication.java

package com.micro.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestMicroServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestMicroServiceApplication.class, args);
    }
}

TestController.java

    package com.micro.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class TestController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value="/micro/order/{id}",
        method=RequestMethod.GET,
        produces=MediaType.ALL_VALUE)
    public String placeOrder(@PathVariable("id") int customerId){

        System.out.println("Hit ===> PlaceOrder");

        Object[] customerJson = restTemplate.getForObject("http://localhost:8080/micro/customers", Object[].class);

        System.out.println(customerJson.toString());

        return "false";
    }

}

POM.xml

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.micro.test</groupId>
    <artifactId>Test-MicroService</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Test-MicroService</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>
Khuzi
quelle
1
Das Abstimmen Ihrer Frage ist nicht offensichtlich, dass, wenn alles magisch verknüpft RestTemplateist, nicht automatisch ein für Sie erstellt wird.
daniel.eichten
Upvoted - Das Tutorial auf der eigenen Seite von Spring Boot sagt nichts über das Erstellen einer RestTemplate Bean aus!
Matt
Ähnlich: stackoverflow.com/q/28024942/86967
Brent Bradburn

Antworten:

173

Genau das sagt der Fehler. Sie haben keine RestTemplateBean erstellt, daher kann sie keine automatisch verdrahten. Wenn Sie eine benötigen, müssen RestTemplateSie eine bereitstellen. Fügen Sie beispielsweise TestMicroServiceApplication.java Folgendes hinzu :

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

Beachten Sie, dass in früheren Versionen des Spring Cloud Starters für Eureka eine RestTemplateBean für Sie erstellt wurde. Dies ist jedoch nicht mehr der Fall.

g00glen00b
quelle
Vielen Dank für Ihre Antwort. Das hat geholfen!
Khuzi
19
Die Frage und Ihre Antwort wurden verbessert. Es ist nicht offensichtlich, dass Sie eine manuell erstellen müssen, RestTemplatewenn alles andere auf magische Weise für Sie erstellt und verknüpft wurde. Vor allem, wenn man eine Frühlingswolke verwendet, vor der eine automatisch konfigurierte bereitgestellt wird RestTemplate. ;-)
daniel.eichten
2
Ehrlich gesagt, das war der Grund, warum ich dieses Thema hier ins Forum gestellt habe. Ich hatte erwartet, dass RestTemplate für mich verlinkt wird. :-) Das hat gut funktioniert, als ich die Eureka-Abhängigkeit in POM.xml aufgenommen hatte. Es funktionierte einwandfrei, ohne RestTemplate Bean zu definieren. Eine der Klassen von Eureka könnte diese Bohne oder so definiert haben.
Khuzi
4
Nur ein Update. Ab Spring Boot RestTemplateBuilderkann 1.4.0 zum Verwalten von RestTemplateInstanzen verwendet werden. Beispiel hier spring.io/guides/gs/consuming-rest
Mensur
Ich kann noch kein Upgrade auf SB 1.4.0 durchführen. Ich möchte dies mit 1.3.8.RELEASE tun, aber die @ g00glen00b-Lösung hat bei mir nicht funktioniert. Ich benutze auch spring-cloud-netflixArtefaktid mit Version 1.1.5.RELEASE. Mein RestTemplate wird von einer @RestControllerJava-Klasse aufgerufen, die @Autowiredfür das verwendet RestTemplate. Kann mir bitte jemand helfen?
ZeroGraviti
33

Abhängig davon, welche Technologien Sie verwenden und welche Versionen Einfluss darauf haben, wie Sie eine RestTemplatein Ihrer @ConfigurationKlasse definieren.

Feder> = 4 ohne Spring Boot

Definieren Sie einfach @Bean:

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

Spring Boot <= 1.3

Sie müssen keine definieren, Spring Boot definiert automatisch eine für Sie.

Spring Boot> = 1.4

Spring Boot definiert nicht mehr automatisch eine, RestTemplatesondern eine RestTemplateBuilder, mit der Sie mehr Kontrolle über die erstellte RestTemplate haben. Sie können das RestTemplateBuilderals Argument in Ihre @BeanMethode einfügen, um Folgendes zu erstellen RestTemplate:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
   // Do any additional configuration here
   return builder.build();
}

Verwenden Sie es in Ihrer Klasse

@Autowired
private RestTemplate restTemplate;

Referenz

Sahil Chhabra
quelle
8

Wenn eine TestRestTemplate eine gültige Option in Ihrem Komponententest ist, ist diese Dokumentation möglicherweise relevant

http://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/reference/htmlsingle/#boot-features-rest-templates-test-utility

Kurze Antwort: wenn mit

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

dann @Autowiredwird es funktionieren. Bei Verwendung

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

Erstellen Sie dann eine TestRestTemplate wie folgt

private TestRestTemplate template = new TestRestTemplate();
Mark K.
quelle
1

Der Fehler weist direkt darauf hin, dass die RestTemplateBean nicht im Kontext definiert ist und die Beans nicht laden kann.

  1. Definieren Sie eine Bean für RestTemplate und verwenden Sie sie dann
  2. Verwenden Sie eine neue Instanz der RestTemplate

Wenn Sie sicher sind, dass die Bean für die RestTemplate definiert ist, verwenden Sie Folgendes, um die Beans zu drucken, die in dem von der Spring Boot-Anwendung geladenen Kontext verfügbar sind

ApplicationContext ctx = SpringApplication.run(Application.class, args);
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
    System.out.println(beanName);
}

Wenn dies die Bohne mit dem angegebenen Namen / Typ enthält, dann ist alles gut. Oder definieren Sie eine neue Bohne und verwenden Sie sie dann.

VinayVeluri
quelle
1

Da RestTemplate-Instanzen häufig vor der Verwendung angepasst werden müssen, bietet Spring Boot keine einzige automatisch konfigurierte RestTemplate-Bean.

RestTemplateBuilder bietet die richtige Möglichkeit, die Rest Template Bean zu konfigurieren und zu instanziieren, z. B. für grundlegende Authentifizierungs- oder Interceptors.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
                .basicAuthorization("user", "name") // Optional Basic auth example
                .interceptors(new MyCustomInterceptor()) // Optional Custom interceptors, etc..
                .build();
}
Pierrick HYMBERT
quelle
1
  • Sie müssen hinzufügen @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ return builder.build(); }
Ranushka Lakmal Sankalpa
quelle
0

Bitte stellen Sie zwei Dinge sicher:

1- Verwenden Sie @BeanAnnotation mit der Methode.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
    return builder.build();
}

2- Der Umfang dieser Methode sollte öffentlich und nicht privat sein .

Vollständiges Beispiel -

@Service
public class MakeHttpsCallImpl implements MakeHttpsCall {

@Autowired
private RestTemplate restTemplate;

@Override
public String makeHttpsCall() {
    return restTemplate.getForObject("https://localhost:8085/onewayssl/v1/test",String.class);
}

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
    return builder.build();
}
}
Weinstock
quelle
0

Auf einfachste Weise konnte ich eine ähnliche Leistung erzielen, indem ich den folgenden Code verwendete ( Referenz ), aber ich würde vorschlagen, keine API-Aufrufe in Controllern durchzuführen ( SOLID-Prinzipien ). Auch das automatische Verdrahten auf diese Weise ist besser optimiert als die herkömmliche Vorgehensweise.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class TestController {

    private final RestTemplate restTemplate;


    @Autowired
    public TestController(RestTemplateBuilder builder) {
        this.restTemplate = builder.build();
    }

    @RequestMapping(value="/micro/order/{id}", method= RequestMethod.GET, produces= MediaType.ALL_VALUE)
    public String placeOrder(@PathVariable("id") int customerId){

        System.out.println("Hit ===> PlaceOrder");

        Object[] customerJson = restTemplate.getForObject("http://localhost:8080/micro/customers", Object[].class);

        System.out.println(customerJson.toString());

        return "false";
    }
}
Padi Kodwo
quelle
0

Sie versuchen, die restTemplate einzufügen, müssen jedoch eine Konfigurationsklasse erstellen. Dann müssen Sie dort eine Bean erstellen, die Ihnen neues RestTemplate zurückgibt (siehe das folgende Beispiel).

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class YourConfigClass {


    @Bean
    public RestTemplate restTesmplate() {
        return new RestTemplate();
    }

}
Fazle Subhan
quelle