Não foi possível fazer o autowire do campo: RestTemplate no aplicativo Spring boot

109

Estou recebendo a exceção abaixo ao executar o aplicativo de inicialização durante a inicialização:

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

Estou autowiring RestTemplate em meu TestController. Estou usando o Maven para gerenciamento de dependências.

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
fonte
1
Votar positivamente na causa da sua pergunta não é óbvio que, quando tudo está magicamente vinculado, a RestTemplatenão é criado automaticamente para você.
daniel.eichten
Aprovado - o tutorial na página do Spring Boot não diz nada sobre a criação de um bean RestTemplate !!
Matt
Similar: stackoverflow.com/q/28024942/86967
Brent Bradburn

Respostas:

174

É exatamente o que o erro diz. Você não criou nenhum RestTemplatebean, então ele não pode autowire nenhum. Se você precisar de um RestTemplate, deverá fornecer um. Por exemplo, adicione o seguinte a TestMicroServiceApplication.java :

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

Observe que nas versões anteriores do Spring cloud starter para Eureka, um RestTemplatebean foi criado para você, mas isso não é mais verdade.

g00glen00b
fonte
Muito obrigado pela sua resposta. Isso ajudou!
Khuzi de
19
Votei positivamente na pergunta e na causa da sua resposta Não é óbvio que você precisa criar manualmente um RestTemplatequando todo o resto é criado e vinculado magicamente para você. Especialmente se um usado nuvem-primavera antes que fornece um autoconfigurado RestTemplate. ;-)
daniel.eichten
2
Honestamente, esse foi o motivo pelo qual coloquei esse problema aqui no fórum. Eu esperava que o RestTemplate fosse vinculado para mim. :-) Isso estava funcionando bem quando incluí a dependência Eureka no POM.xml. Ele estava funcionando bem sem definir o bean RestTemplate. Uma das classes de Eureka pode ter definido esse feijão ou algo assim.
Khuzi
4
Apenas uma atualização. Do Spring Boot 1.4.0 RestTemplateBuilderpode ser usado para gerenciar RestTemplateinstâncias. Exemplo aqui spring.io/guides/gs/consuming-rest
Mensur
Ainda não consigo atualizar para o SB 1.4.0. Quero fazer isso com 1.3.8.RELEASE, mas a solução @ g00glen00b não funcionou para mim. Também estou usando o spring-cloud-netflixartefato com versão 1.1.5.RELEASE. Meu RestTemplate está sendo chamado de uma @RestControllerclasse java que usa @Autowiredpara o RestTemplate. Alguém pode ajudar por favor ?
ZeroGraviti de
33

Dependendo de quais tecnologias você está usando e quais versões influenciarão como você define um RestTemplateem sua @Configurationclasse.

Spring> = 4 sem Spring Boot

Basta definir um @Bean:

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

Spring Boot <= 1,3

Não há necessidade de definir um, Spring Boot define um automaticamente para você.

Spring Boot> = 1,4

Spring Boot não define mais automaticamente um, RestTemplatemas em vez disso define um, RestTemplateBuilderpermitindo a você mais controle sobre o RestTemplate que é criado. Você pode injetar o RestTemplateBuildercomo um argumento em seu @Beanmétodo para criar um RestTemplate:

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

Usar em sua aula

@Autowired
private RestTemplate restTemplate;

Referência

Sahil Chhabra
fonte
8

Se um TestRestTemplate for uma opção válida em seu teste de unidade, esta documentação pode ser relevante

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

Resposta curta: se estiver usando

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

então @Autowiredvai funcionar. Se estiver usando

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

em seguida, crie um TestRestTemplate como este

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

Erro aponta diretamente que o RestTemplatebean não está definido no contexto e não pode carregar os beans.

  1. Defina um bean para RestTemplate e então use-o
  2. Use uma nova instância do RestTemplate

Se você tiver certeza de que o bean está definido para o RestTemplate, use o seguinte para imprimir os beans que estão disponíveis no contexto carregado pelo aplicativo Spring Boot

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

Se contiver o bean pelo nome / tipo fornecido, tudo bem. Ou então defina um novo bean e use-o.

VinayVeluri
fonte
1

Como as instâncias RestTemplate geralmente precisam ser personalizadas antes de serem usadas, o Spring Boot não fornece nenhum bean RestTemplate auto-configurado.

RestTemplateBuilder oferece uma maneira adequada de configurar e instanciar o bean de modelo rest, por exemplo, para autenticação básica ou interceptores.

@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
fonte
1
  • Você deve adicionar @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ return builder.build(); }
Ranushka Lakmal Sankalpa
fonte
0

Certifique-se de duas coisas:

1- Use @Beananotação com o método.

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

2- O escopo deste método deve ser público e não privado .

Exemplo Completo -

@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();
}
}
vinha
fonte
0

A maneira mais simples que consegui alcançar um feito semelhante é usar o código abaixo ( referência ), mas eu sugeriria não fazer chamadas de API em controladores ( princípios SOLID ). Além disso, o autowiring dessa maneira é melhor otimizado do que a maneira tradicional de fazê-lo.

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
fonte
0

você está tentando injetar o restTemplate, mas precisa criar uma classe de configuração. então você precisa criar o bean que retorna seu novo RestTemplate, veja o exemplo abaixo.

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
fonte