Tidak dapat melakukan autowire bidang: RestTemplate dalam aplikasi boot Spring


109

Saya mendapatkan pengecualian di bawah ini saat menjalankan aplikasi boot musim semi selama start up:

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

Saya memasang RestTemplate secara otomatis di TestController saya. Saya menggunakan Maven untuk manajemen ketergantungan.

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
Meningkatkan pertanyaan Anda karena tidak jelas bahwa ketika semuanya terhubung secara ajaib, RestTemplatetidak secara otomatis dibuat untuk Anda.
daniel.eichten

Suara positif - tutorial di halaman Spring Boot tidak menjelaskan apa pun tentang membuat RestTemplate Bean !!
Matt

Jawaban:


174

Persis seperti itulah yang dikatakan kesalahan. Anda tidak membuat RestTemplatekacang apa pun , jadi tidak bisa membuat autowire apa pun. Jika Anda membutuhkan, RestTemplateAnda harus menyediakannya. Misalnya, tambahkan yang berikut ini ke TestMicroServiceApplication.java :

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

Perhatikan, di versi awal Spring cloud starter untuk Eureka, RestTemplatekacang telah dibuat untuk Anda, tetapi ini tidak berlaku lagi.


Terima kasih banyak atas balasan Anda. Ini membantu!
Khuzi

19
Suara positif pertanyaan dan jawaban Anda menyebabkan Tidak jelas bahwa Anda harus membuat secara manual RestTemplateketika segala sesuatu yang lain secara ajaib dibuat dan ditautkan untuk Anda. Terutama jika seseorang menggunakan spring-cloud sebelumnya yang menyediakan konfigurasi otomatis RestTemplate. ;-)
daniel.eichten

2
Sejujurnya, itulah alasan saya meletakkan masalah ini di sini di forum. Saya mengharapkan RestTemplate ditautkan untuk saya. :-) Ini berfungsi dengan baik ketika saya memasukkan dependensi Eureka di POM.xml. Itu bekerja dengan baik tanpa mendefinisikan kacang RestTemplate. Salah satu kelas Eureka mungkin telah mendefinisikan kacang ini atau lebih.
Khuzi

4
Hanya pembaruan. Dari Spring Boot 1.4.0 RestTemplateBuilderdapat digunakan untuk mengelola RestTemplateinstans. Contoh di sini spring.io/guides/gs/consuming-rest
Mensur

Saya belum bisa meningkatkan ke SB 1.4.0. Saya ingin melakukan ini dengan 1.3.8.RELEASE tetapi solusi @ g00glen00b tidak berhasil untuk saya. Saya juga menggunakan spring-cloud-netflixartefak dengan versi 1.1.5.RELEASE. RestTemplate saya dipanggil dari @RestControllerkelas java yang digunakan @Autowireduntuk RestTemplate. Dapatkah seseorang tolong bantu ?
ZeroGraviti

33

Bergantung pada teknologi apa yang Anda gunakan dan versi apa yang akan memengaruhi cara Anda mendefinisikan a RestTemplatedi @Configurationkelas Anda .

Spring> = 4 tanpa Spring Boot

Cukup tentukan @Bean:

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

Sepatu Musim Semi <= 1.3

Tidak perlu menentukannya, Spring Boot otomatis menentukannya untuk Anda.

Sepatu Musim Semi> = 1.4

Spring Boot tidak lagi secara otomatis mendefinisikan a RestTemplatemelainkan mendefinisikan RestTemplateBuildermemungkinkan Anda lebih mengontrol RestTemplate yang dibuat. Anda dapat memasukkan RestTemplateBuildersebagai argumen dalam @Beanmetode Anda untuk membuat RestTemplate:

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

Menggunakannya di kelas Anda

@Autowired
private RestTemplate restTemplate;

Referensi


8

Jika TestRestTemplate adalah opsi yang valid dalam pengujian unit Anda, dokumentasi ini mungkin relevan

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

Jawaban singkatnya: jika menggunakan

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

maka @Autowiredakan berhasil. Jika menggunakan

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

kemudian buat TestRestTemplate seperti ini

private TestRestTemplate template = new TestRestTemplate();

1

Kesalahan menunjukkan secara langsung bahwa RestTemplatekacang tidak didefinisikan dalam konteks dan tidak dapat memuat kacang.

  1. Tentukan kacang untuk RestTemplate dan kemudian gunakan
  2. Gunakan contoh baru dari RestTemplate

Jika Anda yakin bahwa kacang ditentukan untuk RestTemplate kemudian gunakan yang berikut ini untuk mencetak kacang yang tersedia dalam konteks yang dimuat oleh aplikasi boot musim semi

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

Jika ini berisi kacang dengan nama / jenis yang diberikan, maka semuanya bagus. Atau definisikan kacang baru dan kemudian gunakan.


1

Karena instans RestTemplate sering kali perlu disesuaikan sebelum digunakan, Spring Boot tidak menyediakan kacang RestTemplate yang dikonfigurasi secara otomatis.

RestTemplateBuilder menawarkan cara yang tepat untuk mengkonfigurasi dan membuat instance kacang template lainnya, misalnya untuk autentikasi dasar atau interseptor.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
                .basicAuthorization("user", "name") // Optional Basic auth example
                .interceptors(new MyCustomInterceptor()) // Optional Custom interceptors, etc..
                .build();
}


0

Harap pastikan dua hal:

1- Gunakan @Beananotasi dengan metode.

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

2- Cakupan metode ini harus publik, bukan privat .

Contoh Lengkap -

@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

Cara paling sederhana saya dapat mencapai prestasi serupa dengan menggunakan kode di bawah ini ( referensi ), tetapi saya menyarankan untuk tidak membuat panggilan API dalam pengontrol ( prinsip SOLID ). Juga autowiring dengan cara ini lebih dioptimalkan daripada cara tradisional melakukannya.

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

Anda mencoba memasukkan restTemplate tetapi Anda perlu membuat kelas konfigurasi. maka di sana Anda perlu membuat kacang yang mengembalikan Anda RestTemplate baru lihat contoh di bawah ini.

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


@Configuration
public class YourConfigClass {


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

}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.