Не удалось выполнить автоматическое подключение поля: RestTemplate в приложении загрузки Spring

115

Я получаю исключение ниже при запуске приложения загрузки Spring во время запуска:

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

Я автоматически подключаю RestTemplate в своем TestController. Я использую Maven для управления зависимостями.

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
Голосование за ваш вопрос не очевидно, потому что, когда все волшебным образом связано, RestTemplateавтоматически не создается для вас.
daniel.eichten,
Проголосовали за - в руководстве на собственной странице Spring Boot ничего не говорится о создании компонента RestTemplate!
Мэтт
Похожее: stackoverflow.com/q/28024942/86967
Брент Брэдберн

Ответы:

177

Это именно то, о чем говорит ошибка. Вы не создавали RestTemplatebean-компонент, поэтому он не может автоматически подключать его. Если вам нужен, вам нужно RestTemplateбудет его предоставить. Например, добавьте в TestMicroServiceApplication.java следующее :

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

Обратите внимание, что в более ранних версиях Spring Cloud Starter для Eureka RestTemplateкомпонент был создан для вас, но это уже не так.

g00glen00b
источник
Большое спасибо за ваш ответ. Это помогло!
Хузи,
20
Проголосовали за вопрос и ваш ответ. Причина. Не очевидно, что вам нужно вручную создавать, RestTemplateкогда все остальное волшебным образом создается и связывается для вас. Особенно, если раньше использовали spring -cloud, который обеспечивает автоконфигурацию RestTemplate. ;-)
daniel.eichten
2
Честно говоря, именно по этой причине я разместил этот вопрос на форуме. Я ожидал, что RestTemplate будет связан за меня. :-) Это работало нормально, когда я включил зависимость Eureka в POM.xml. Он работал нормально без определения bean-компонента RestTemplate. Один из классов Eureka мог определить этот компонент или около того.
Khuzi
4
Просто обновление. Начиная с Spring Boot 1.4.0 RestTemplateBuilderможно использовать для управления RestTemplateэкземплярами. Пример здесь spring.io/guides/gs/consuming-rest
Mensur
Пока не могу перейти на SB 1.4.0. Я хочу сделать это с помощью 1.3.8.RELEASE, но решение @ g00glen00b у меня не сработало. Я также использую spring-cloud-netflixartifactid с версией 1.1.5.RELEASE. My RestTemplate вызывается из @RestControllerкласса java, который использует @Autowiredдля RestTemplate. Может кто-нибудь помочь?
ZeroGraviti
35

В зависимости от того, какие технологии вы используете и какие версии будут влиять на то, как вы определяете RestTemplateв своем @Configurationклассе.

Spring> = 4 без Spring Boot

Просто определите @Bean:

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

Spring Boot <= 1.3

Нет необходимости определять один, Spring Boot автоматически определяет его за вас.

Spring Boot> = 1,4

Spring Boot больше не определяет автоматически, RestTemplateа вместо этого определяет, что RestTemplateBuilderпозволяет вам больше контролировать создаваемый RestTemplate. Вы можете ввести в RestTemplateBuilderкачестве аргумента в свой @Beanметод, чтобы создать RestTemplate:

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

Использование в вашем классе

@Autowired
private RestTemplate restTemplate;

Ссылка

Сахил Чабра
источник
8

Если TestRestTemplate является допустимым вариантом в вашем модульном тесте, эта документация может быть актуальной.

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

Краткий ответ: при использовании

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

тогда @Autowiredбудет работать. При использовании

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

затем создайте TestRestTemplate, подобный этому

private TestRestTemplate template = new TestRestTemplate();
Марк К.
источник
1

Ошибка прямо указывает на то, что RestTemplateкомпонент не определен в контексте и не может загрузить его.

  1. Определите bean-компонент для RestTemplate, а затем используйте его
  2. Используйте новый экземпляр RestTemplate

Если вы уверены, что bean-компонент определен для RestTemplate, используйте следующее, чтобы распечатать beans, которые доступны в контексте, загруженном приложением загрузки Spring

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

Если он содержит bean-компонент с указанным именем / типом, тогда все в порядке. Или же определите новый bean-компонент и затем используйте его.

ВинайВелури
источник
1

Поскольку экземпляры RestTemplate часто необходимо настраивать перед использованием, Spring Boot не предоставляет ни одного автоматически настраиваемого bean-компонента RestTemplate.

RestTemplateBuilder предлагает правильный способ настройки и создания экземпляра остального компонента шаблона, например, для базовой аутентификации или перехватчиков.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
                .basicAuthorization("user", "name") // Optional Basic auth example
                .interceptors(new MyCustomInterceptor()) // Optional Custom interceptors, etc..
                .build();
}
Пьеррик ГИМБЕРТ
источник
1
  • Вы должны добавить @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ return builder.build(); }
Ранушка Лакмал Санкальпа
источник
0

Пожалуйста, убедитесь в двух вещах:

1- Используйте @Beanаннотацию к методу.

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

2- Область применения этого метода должна быть публичной, а не частной .

Полный пример -

@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

Самый простой способ, которым я смог добиться аналогичного результата, - использовать приведенный ниже код ( ссылка ), но я бы посоветовал не выполнять вызовы API в контроллерах ( принципы SOLID ). Также автоматическое подключение таким способом лучше оптимизировать, чем традиционный способ.

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

вы пытаетесь ввести restTemplate, но вам нужно создать класс конфигурации. тогда вам нужно создать bean-компонент, который вернет вам новый RestTemplate, см. пример ниже.

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


@Configuration
public class YourConfigClass {


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

}
Фазл Субхан
источник