Trường không thể tự động truyền tải: RestTemplate trong ứng dụng khởi động Spring


109

Tôi nhận được ngoại lệ dưới đây khi chạy ứng dụng khởi động mùa xuân trong khi khởi động:

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

Tôi đang tự động tạo RestTemplate trong TestController của mình. Tôi đang sử dụng Maven để quản lý sự phụ thuộc.

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
Ủng hộ câu hỏi của bạn vì không rõ ràng là khi mọi thứ được liên kết một cách kỳ diệu, a RestTemplatekhông được tạo tự động cho bạn.
daniel.eichten

Được ủng hộ - hướng dẫn trên trang riêng của Spring Boot không nói gì về việc tạo RestTemplate Bean !!
Matt

Câu trả lời:


174

Đó chính xác là những gì lỗi nói. Bạn không tạo bất kỳ RestTemplatebean nào , vì vậy nó không thể tự động chạy bất kỳ. Nếu bạn cần, RestTemplatebạn sẽ phải cung cấp một. Ví dụ: thêm phần sau vào TestMicroServiceApplication.java :

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

Lưu ý, trong các phiên bản trước của Spring cloud starter cho Eureka, một RestTemplatebean đã được tạo cho bạn, nhưng điều này không còn đúng nữa.


Cảm ơn rất nhiều cho trả lời của bạn. Điều này đã giúp!
Khuzi

19
Đã ủng hộ câu hỏi và nguyên nhân câu trả lời của bạn Không rõ ràng là bạn phải tạo thủ công RestTemplatekhi mọi thứ khác được tạo và liên kết một cách kỳ diệu cho bạn. Đặc biệt là nếu trước đó một người đã sử dụng Spring-cloud cung cấp cấu hình tự động RestTemplate. ;-)
daniel.eichten

2
Thành thật mà nói, đó là lý do tôi đặt vấn đề này ở đây trong diễn đàn. Tôi đã mong đợi RestTemplate được liên kết cho tôi. :-) Điều này hoạt động tốt khi tôi đã bao gồm phụ thuộc Eureka trong POM.xml. Nó hoạt động tốt mà không cần xác định bean RestTemplate. Một trong những lớp của Eureka có thể đã định nghĩa hạt đậu này hoặc tương tự.
Khuzi

4
Chỉ là một bản cập nhật. Từ Spring Boot 1.4.0 RestTemplateBuildercó thể được sử dụng để quản lý các RestTemplatephiên bản. Ví dụ ở đây spring.io/guides/gs/consuming-rest
Mensur

Tôi vẫn chưa thể nâng cấp lên SB 1.4.0. Tôi muốn thực hiện việc này với 1.3.8.RELEASE nhưng giải pháp @ g00glen00b không hoạt động với tôi. Tôi cũng đang sử dụng spring-cloud-netflixArfactid với phiên bản 1.1.5.RELEASE. RestTemplate của tôi đang được gọi từ một @RestControllerlớp java sử dụng @Autowiredcho RestTemplate. Ai đó có thể vui lòng giúp đỡ?
ZeroGraviti,

33

Tùy thuộc vào công nghệ bạn đang sử dụng và phiên bản nào sẽ ảnh hưởng đến cách bạn xác định một RestTemplatetrong @Configurationlớp của mình .

Spring> = 4 không có Spring Boot

Đơn giản chỉ cần xác định một @Bean:

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

Khởi động mùa xuân <= 1.3

Không cần xác định một cái, Spring Boot tự động xác định một cái cho bạn.

Khởi động mùa xuân> = 1.4

Spring Boot không còn tự động xác định một RestTemplatemà thay vào đó xác định một RestTemplateBuildercho phép bạn kiểm soát nhiều hơn đối với RestTemplate được tạo. Bạn có thể chèn tham số RestTemplateBuilderdưới dạng đối số trong @Beanphương thức của mình để tạo RestTemplate:

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

Sử dụng nó trong lớp học của bạn

@Autowired
private RestTemplate restTemplate;

Tài liệu tham khảo


8

Nếu TestRestTemplate là một tùy chọn hợp lệ trong bài kiểm tra đơn vị của bạn, thì tài liệu này có thể có liên quan

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

Câu trả lời ngắn gọn: nếu sử dụng

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

sau đó @Autowiredsẽ hoạt động. Nếu sử dụng

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

sau đó tạo TestRestTemplate như thế này

private TestRestTemplate template = new TestRestTemplate();

1

Lỗi chỉ trực tiếp rằng RestTemplatebean không được xác định trong ngữ cảnh và nó không thể tải các bean.

  1. Xác định một bean cho RestTemplate và sau đó sử dụng nó
  2. Sử dụng phiên bản mới của RestTemplate

Nếu bạn chắc chắn rằng bean được xác định cho RestTemplate thì hãy sử dụng phần sau để in các bean có sẵn trong ngữ cảnh được tải bởi ứng dụng khởi động mùa xuân

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

Nếu nó chứa bean theo tên / loại đã cho, thì tất cả đều tốt. Hoặc nếu không, hãy xác định một bean mới và sau đó sử dụng nó.


1

Vì các phiên bản RestTemplate thường cần được tùy chỉnh trước khi được sử dụng, Spring Boot không cung cấp bất kỳ bean RestTemplate nào được cấu hình tự động.

RestTemplateBuilder cung cấp cách thích hợp để định cấu hình và khởi tạo bean mẫu còn lại, ví dụ như đối với các trình đánh chặn hoặc xác thực cơ bản.

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


0

Hãy đảm bảo hai điều:

1- Sử dụng @Beanchú thích với phương thức.

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

2- Phạm vi của phương pháp này nên công khai không riêng tư .

Ví dụ hoàn chỉnh -

@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

Cách đơn giản nhất mà tôi có thể đạt được thành tích tương tự là sử dụng mã bên dưới ( tham khảo ), nhưng tôi khuyên bạn không nên thực hiện lệnh gọi API trong bộ điều khiển ( nguyên tắc SOLID ). Ngoài ra autowiring theo cách này sẽ tốt hơn so với cách làm truyền thống.

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

bạn đang cố gắng đưa vào restTemplate nhưng bạn cần tạo lớp cấu hình. thì ở đó bạn cần tạo bean trả về cho bạn RestTemplate mới, hãy xem ví dụ bên dưới.

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


@Configuration
public class YourConfigClass {


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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.