java uses Feign to implement declarative Restful style calls

  • 2021-07-24 10:54:12
  • OfStack

1. Introduction to Feign

Feign is a declarative, templated http client developed by netflix, which is used like calling the local (service consumer's own) method 1, helping us to call the service provider's API more gracefully. Feign itself supports springMVC, and integrates Eureka and Ribbon, which greatly simplifies the use of Feign. As far as integrating Euraka is concerned, you only need to configure the information of Eureka and server with ordinary services. Integrating Ribbon means that there is no need to invoke service provider methods through instantiated RestTemplate labeled @ LoadBalanced. Feign can achieve load balancing by simply defining one interface.

2. Using Feign among service consumers

1. Add Feign dependencies


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

2. Create an feign interface with @ FeignClient annotation in the header


import com.simons.cn.util.CommonResult;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
 
@FeignClient(name = "user-provider")
public interface UserFeignService {
 
  @RequestMapping(value = "/getuserinfo",method = RequestMethod.GET)
  CommonResult getUserByName(@RequestParam(required = false,value = "name") String name);
 
}

Here, name= "user-provider" will be resolved as one of the clients registered on Eureka server, in other words, one of the services registered on Eureka, which can be used for load balancing. You can also specify @ FeignClient in conjunction with value (name= "user-provider", value = "http://localhost: 8000/")

3. Modify Controller, instead of calling RestTemplate annotated by @ LoadBalanced, it annotates the custom interface of @ FeignClient


import com.simons.cn.UserFeignService;
import com.simons.cn.util.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
@Slf4j
@RestController
public class TicketFeignController {
 
  @Autowired
  private UserFeignService userFeignService;
 
  @GetMapping("/ticketpurchase")
  public CommonResult purchaseTicket(@RequestParam(required = false,value = "name") String name){
    CommonResult result = userFeignService.getUserByName(name);
    return result;
  }
 
}

4. Modify the startup class and add @ EnableFeignClients annotation to the header


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
 
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class TicketConsumerFeignApplication {
 
  public static void main(String[] args) {
    SpringApplication.run(TicketConsumerFeignApplication.class, args);
  }
}

Test:

Start multiple user-provider-eureka service instances with application. name=user-provider in the configuration file;

Start the discovery-eureka service instance;

Start the ticket-consumer-feign service instance

From the above test results, we can see that ticket-consumer-feign consumers successfully call the methods of user-provider-eureka service providers, and realize load balancing.

3. Constructing multi-parameter requests using Feign

1. get request: multiple parameters are marked with multiple @ RequestParam


@FeignClient(name = "user-provider")
public interface UserFeignService {
 
  @RequestMapping(value = "/getuserinfo",method = RequestMethod.GET)
  CommonResult getUserByName(@RequestParam(required = false,value = "name") String name);
 
}

Or use Map to encapsulate the parameters


@FeignClient(name="user-provider")
public interface UserServiceFeign {
  @RequestMapping(value = "/getuserinfo",method = RequestMethod.GET)
  public CommonResult getUserByName(@RequestParam Map<String,Object> map);
}

@RestController
public class TicketController {
  @Autowired
  private UserServiceFeign userServiceFeign;
 
  @GetMapping("ticketpurchase")
  public CommonResult (Long id, String actId) {
    Map map = new HashMap<String, Object>();
    map.put("id", id);
    map.put("actId", actId);
    return this.userServiceFeign.getUserByName(map);
  }
}

2. post requests are much simpler


//  Service consumer side 
@FeignClient(name="user-provider")
public interface UserServiceFeign {
 
  @RequestMapping(value="/getuserbyname",method = RequestMethod.POST)
  public COmmonResult getUserByName(@RequestBody User user);
 
}

// Service provider 
@Slf4j
@RestController
public class UserController {
 
  @Autowired
  private UserServiceImpl userService;
 
  @GetMapping(value = "/getuserinfo")
  public CommonResult getUserInfo(@RuquestBody User user){
    List<User> userList = userService.getUserByName(user.getName());
    return CommonResult.success(CommonEnum.SUCESS.getCode(), CommonEnum.SUCESS.getMessage(),userList);
  }
}

github for the project


Related articles: