No se pudo conectar automáticamente el campo: RestTemplate en la aplicación de arranque Spring

109

Recibo la siguiente excepción al ejecutar la aplicación de arranque de primavera durante el inicio:

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

Estoy conectando automáticamente RestTemplate en mi TestController. Estoy usando Maven para la gestión de dependencias.

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
fuente
1
Votar a favor su pregunta porque no es obvio que cuando todo está vinculado mágicamente RestTemplateno se crea automáticamente para usted.
daniel.eichten
Upvoted: ¡el tutorial en la propia página de Spring Boot no dice nada sobre la creación de un RestTemplate Bean!
Matt
Similar: stackoverflow.com/q/28024942/86967
Brent Bradburn

Respuestas:

174

Es exactamente lo que dice el error. No creó ningún RestTemplatebean, por lo que no se puede conectar automáticamente. Si necesita RestTemplateuno, tendrá que proporcionar uno. Por ejemplo, agregue lo siguiente a TestMicroServiceApplication.java :

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

Tenga en cuenta que en versiones anteriores del iniciador de nubes Spring para Eureka, RestTemplatese creó un bean para usted, pero esto ya no es cierto.

g00glen00b
fuente
Muchas gracias por tu respuesta. ¡Esto ayudó!
Khuzi
19
Votó a favor la pregunta y su respuesta porque no es obvio que tenga que crear manualmente un RestTemplatecuando todo lo demás se crea y se vincula mágicamente para usted. Especialmente si se usó spring-cloud antes, lo que proporciona un archivo autoconfigurado RestTemplate. ;-)
daniel.eichten
2
Honestamente, esa fue la razón por la que puse este tema aquí en el foro. Esperaba que RestTemplate estuviera vinculado por mí. :-) Esto funcionaba bien cuando incluí la dependencia de Eureka en POM.xml. Funcionaba bien sin definir el bean RestTemplate. Una de las clases de Eureka podría haber definido este bean más o menos.
Khuzi
4
Solo una actualización. Desde Spring Boot 1.4.0 RestTemplateBuilderse puede usar para administrar RestTemplateinstancias. Ejemplo aquí spring.io/guides/gs/consuming-rest
Mensur
Todavía no puedo actualizar a SB 1.4.0. Quiero hacer esto con 1.3.8.RELEASE pero la solución @ g00glen00b no funcionó para mí. También estoy usando spring-cloud-netflixartifactid con la versión 1.1.5.RELEASE. Mi RestTemplate está siendo llamado desde una @RestControllerclase java que usa @Autowiredpara RestTemplate. Puede ayudarme alguien, por favor ?
ZeroGraviti
33

Dependiendo de las tecnologías que esté utilizando y las versiones que influirán en cómo define a RestTemplateen su @Configurationclase.

Spring> = 4 sin Spring Boot

Simplemente defina un @Bean:

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

Arranque de primavera <= 1.3

No es necesario definir uno, Spring Boot define uno automáticamente para usted.

Bota de primavera> = 1.4

Spring Boot ya no define automáticamente a, RestTemplatesino que define a, RestTemplateBuilderlo que le permite más control sobre la RestTemplate que se crea. Puede inyectar el RestTemplateBuildercomo argumento en su @Beanmétodo para crear un RestTemplate:

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

Usándolo en tu clase

@Autowired
private RestTemplate restTemplate;

Referencia

Sahil Chhabra
fuente
8

Si un TestRestTemplate es una opción válida en su prueba unitaria, esta documentación puede ser relevante

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

Respuesta corta: si usa

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

entonces @Autowiredfuncionará. Si usa

@SpringBootTest(webEnvironment=WebEnvironment.MOCK)

luego crea un TestRestTemplate como este

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

El error apunta directamente a que el RestTemplatebean no está definido en contexto y no puede cargar los beans.

  1. Defina un bean para RestTemplate y luego úselo
  2. Usar una nueva instancia de RestTemplate

Si está seguro de que el bean está definido para RestTemplate, utilice lo siguiente para imprimir los beans que están disponibles en el contexto cargado por la aplicación Spring Boot

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

Si contiene el bean por el nombre / tipo dado, entonces todo está bien. O bien, defina un nuevo bean y luego úselo.

VinayVeluri
fuente
1

Dado que las instancias de RestTemplate a menudo deben personalizarse antes de usarse, Spring Boot no proporciona ningún bean RestTemplate autoconfigurado.

RestTemplateBuilder ofrece una forma adecuada de configurar e instanciar el bean de plantilla rest, por ejemplo, para la autenticación básica o 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
fuente
1
  • Debes agregar @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ return builder.build(); }
Ranushka Lakmal Sankalpa
fuente
0

Asegúrese de dos cosas:

1- Utilice @Beananotación con el método.

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

2- El alcance de este método debe ser público, no privado .

Ejemplo 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();
}
}
vineet
fuente
0

La forma más sencilla en que pude lograr una hazaña similar fue usar el código a continuación ( referencia ), pero sugeriría no hacer llamadas a API en controladores ( principios SOLID ). Además, el cableado automático de esta manera está mejor optimizado que la forma tradicional de hacerlo.

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

está intentando inyectar restTemplate pero necesita crear una clase de configuración. Luego, debe crear un bean que le devuelva una nueva RestTemplate, vea el siguiente ejemplo.

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
fuente