Search code examples
javaspringspring-bootoauth-2.0feign

Communication between microservices using Feign throws bean could not be found


I'm trying to get my microservice java spring boot to communicate with another microservice using Feign but I'm getting this message when starting the application:

APPLICATION FAILED TO START
***************************
Description: Parameter 0 of constructor in ProductService required a bean of type ProductClientRepository' that could not be found.

Action: Consider defining a bean of type 'ProductClientRepository' in your configuration.

I don't know what could be wrong, I already checked if all the declared variables are in the project's properties and I already checked the imports, I don't know why it is saying that something is missing in the bean.

pom.xml:

       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

SaleService:

@Service
@RequiredArgsConstructor
public class SaleService {

 private final ProductService productService;

 @Transactional
    public Sale createSale(Sale sale) {

        Set<Long> codesFromRequest = sale.getProducts().stream().map(p -> p.getCode())
                .collect(Collectors.toSet());
        validateProduct(codesFromRequest);

       return saleRepository.save(sale);
       
    }

    public void validateProduct(Set<Long> codesFromRequest) {
        List<SaleProductDTO> products = productService.findProduct(codesFromRequest);

        Set<Long> returnedCodes = products.stream().map(p -> p.getCode()).collect(Collectors.toSet());

        throwExceptionIf(validateSizeList(codesFromRequest, returnedCodes),
                new ProductNotFoundException());
    }

    public boolean validateSizeList(Collection<?> codesFromRequest, Collection<?> returnedCodes) {
        return codesFromRequest.size() != returnedCodes.size();
    }

}

ProductService:

@Service
@Slf4j
@AllArgsConstructor
public class ProductService {

    private final ProductClientRepository productRepository;

    @Retryable(value = { Exception.class }, maxAttempts = 3, backoff = @Backoff(delay = 50))
    public List<SaleProductDTO> findProduct(Set<Long> codes) {

        Page<SaleProductDTO> resultPage;

        try {
            var search = SearchProductDTO
                    .builder()
                    .codes(codes)
                    .build();

            resultPage = productRepository.getProducts(search);
        } catch (FeignException f) {
            return Collections.emptyList();
        }

        return resultPage.getContent();
    }
}

ProductClientRepository:

@FeignClient(name = "product-service", url = "${ms-product.url}", configuration = ProductOAuth2FeignConfig.class)
public interface ProductClientRepository {

    @GetMapping(value = "/chunk")
    Page<SaleProductDTO> getProducts(@RequestBody SearchProductDTO searchDTO);
}

ProductOAuth2FeignConfig:

public class ProductOAuth2FeignConfig {

    @Autowired
    private ProductConfig productConfig;

    @Bean
    public RequestInterceptor stockOAuth2RequestInterceptor() {
        return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), resource());
    }

    private OAuth2ProtectedResourceDetails resource() {
        ClientCredentialsResourceDetails resource = new ClientCredentialsResourceDetails();
        resource.setAccessTokenUri(productConfig.getTokenUri());
        resource.setClientId(productConfig.getTokenClientId());
        resource.setClientSecret(productConfig.getTokenClientSecret());
        resource.setGrantType(productConfig.getTokenGrantType());
        resource.setScope(List.of(productConfig.getTokenScope()));

        return resource;
    }
}

ProductConfig:

@Data
@Configuration
@ConfigurationProperties(prefix = "ms-product")
public class ProductConfig {

    private String tokenUri;
    private String tokenGrantType;
    private String tokenClientId;
    private String tokenClientSecret;
    private String tokenScope;
}

application.properties:

external.api=https://myadress.com/api

ms-product.url=${external.api}/products
ms-product.token-uri=${external.api}/products/oauth2/token
ms-product.token-grant-type=client_credentials
ms-product.token-client-id=client-id-value
ms-product.token-client-secret=secret-value
ms-product.token-scope=read

feign.client.config.default.connect-timeout=3000
feign.client.config.default.read-timeout=7000

Solution

  • Seems you need to add @EnableFeignClients annotation. Please refer Spring Boot OpenFeign