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>

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

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.


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


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

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.


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


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

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

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

}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.