This is my setup:
First service(FlightIntegrationApplication) which invoke second service(BaggageServiceApplication) using FeignClients API and Eureka.
Project on github: https://github.com/IdanFridman/BootNetflixExample
First service:
@SpringBootApplication
@EnableCircuitBreaker
@EnableDiscoveryClient
@ComponentScan("com.bootnetflix")
public class FlightIntegrationApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(FlightIntegrationApplication.class).run(args);
}
}
in one of the controllers:
@RequestMapping("/flights/baggage/list/{id}")
public String getBaggageListByFlightId(@PathVariable("id") String id) {
return flightIntegrationService.getBaggageListById(id);
}
FlightIntegrationService:
public String getBaggageListById(String id) {
URI uri = registryService.getServiceUrl("baggage-service", "http://localhost:8081/baggage-service");
String url = uri.toString() + "/baggage/list/" + id;
LOG.info("GetBaggageList from URL: {}", url);
ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);
LOG.info("GetProduct http-status: {}", resultStr.getStatusCode());
LOG.info("GetProduct body: {}", resultStr.getBody());
return resultStr.getBody();
}
RegistryService:
@Named
public class RegistryService {
private static final Logger LOG = LoggerFactory.getLogger(RegistryService.class);
@Autowired
LoadBalancerClient loadBalancer;
public URI getServiceUrl(String serviceId, String fallbackUri) {
URI uri;
try {
ServiceInstance instance = loadBalancer.choose(serviceId);
uri = instance.getUri();
LOG.debug("Resolved serviceId '{}' to URL '{}'.", serviceId, uri);
} catch (RuntimeException e) {
// Eureka not available, use fallback
uri = URI.create(fallbackUri);
LOG.error("Failed to resolve serviceId '{}'. Fallback to URL '{}'.", serviceId, uri);
}
return uri;
}
}
And this is the second service (baggage-service):
BaggageServiceApplication:
@Configuration
@ComponentScan("com.bootnetflix")
@EnableAutoConfiguration
@EnableEurekaClient
@EnableFeignClients
public class BaggageServiceApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(BaggageServiceApplication.class).run(args);
}
}
BaggageService:
@FeignClient("baggage-service")
public interface BaggageService {
@RequestMapping(method = RequestMethod.GET, value = "/baggage/list/{flight_id}")
List<String> getBaggageListByFlightId(@PathVariable("flight_id") String flightId);
}
BaggageServiceImpl:
@Named
public class BaggageServiceImpl implements BaggageService{
....
@Override
public List<String> getBaggageListByFlightId(String flightId) {
return Arrays.asList("2,3,4");
}
}
When invoking the rest controller of flight integration service I get:
2015-07-22 17:25:40.682 INFO 11308 --- [ XNIO-2 task-3] c.b.f.service.FlightIntegrationService : GetBaggageList from URL: http://X230-Ext_IdanF:62007/baggage/list/4
2015-07-22 17:25:43.953 ERROR 11308 --- [ XNIO-2 task-3] io.undertow.request : UT005023: Exception handling request to /flights/baggage/list/4
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 404 Not Found
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
Any idea ?
Thanks, ray.
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations.
Error Decoder for Feign client You can use error-decoder to act based on the erroneous HTTP responses. I have observed that error-decoder does not get triggered on success scenarios. To implement an error-decoder, you need to implement a class using ErrorDecoder interface and add that in the configuration.
A central concept in Spring Cloud's Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation.
Your code looks backwards to me.
The feign client for the baggage service should be declared in the flight service and the baggage service should have a controller that responds on the URL you map in your baggage service client, you should not implement the interface annotated with @FeignClient
.
The setup you have now will not have any controller listening on /baggage/list/{flightId} in the baggage service and no Feign client in flight service - the whole point of Feign is to call methods on an interface instead of manually handling URLs, Spring Cloud takes care of auto-instantiating the interface implementation and will use Eureka for discovery.
Try this (or modify so it fits your real world app):
Flight Service:
FlightIntegrationService.java:
@Component
public class FlightIntegrationService {
@Autowired
BaggageService baggageService;
public String getBaggageListById(String id) {
return baggageService.getBaggageListByFlightId(id);
}
}
BaggageService.java:
@FeignClient("baggage-service")
public interface BaggageService {
@RequestMapping(method = RequestMethod.GET, value = "/baggage/list/{flight_id}")
List<String> getBaggageListByFlightId(@PathVariable("flight_id") String flightId);
}
Baggage Service:
BaggageController.java:
@RestController
public class BaggageController {
@RequestMapping("/baggage/list/{flightId}")
public List<String> getBaggageListByFlightId(@PathVariable String flightId) {
return Arrays.asList("2,3,4");
}
}
Remove BaggageService.java and BaggageServiceImpl.java from the Baggage Service
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With