酷播亮新聞
最棒的知識補給站

Sprig Cloud(五):Feign

簡介

快速入門

restTemplate.getForObject("http://flim-user/"+id,User.class);
Map map = new HashMap<>();map.put("name","張三");map.put("username","account1");map.put("age",20);this.restTemplate.getForObject(" http://localhost:8010/search?name={name}&username={username}&age={age}",User[].class,map);

服務消費者整合 Feign

 org.springframework.cloud spring-cloud-starter-feign 1.4.4.RELEASE
@FeignClient(name = "film-user") // 服務提供者名稱public interface UserFeignClient { @GetMapping("/{id}") UserEntity findById(@PathVariable("id") int id);}
  • 由於使用 Eureka,film-user 會被解析成 Eureka Server 中註冊的微服務,若不想使用 Eureka,可以使用 service.ribbon.listOfServers 屬性配置服務列表

  • 還可使用 url 屬性指定請求 URL

@FeignClient(name = "film-user",url = "http://localhost:8080")
@Autowiredprivate UserFeignClient userFeignClient;@GetMapping("/user/{id}")public UserEntity findById(@PathVariable int id){ return userFeignClient.findById(id);}

自定義 Feign 配置

@Configurationpublic class FeignConfiguration { //使用Feign自帶的註解 @Bean public Contract feignContract(){ return new feign.Contract.Default(); }}
@FeignClient(name = "film-user",configuration = FeignConfiguration.class)public interface UserFeignClient { //使用Feign自帶的註解@RequestLine @RequestLine("GET /{id}") UserEntity findById(@PathVariable("id") int id);}

手動建立 Feign

修改服務提供者

 org.springframework.boot spring-boot-starter-security
@[email protected]@EnableGlobalMethodSecurity(prePostEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("password1").roles("USER") .and() .withUser("admin").password("password2").roles("ADMIN") .and() .passwordEncoder(this.passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { //所有請求都要經過httpBasic認證 http.authorizeRequests().anyRequest().authenticated().and().httpBasic(); } @Bean public PasswordEncoder passwordEncoder(){ //返回一個明文密碼器,Spring 提供給我們做明文測試的 return NoOpPasswordEncoder.getInstance(); }}
@RestControllerpublic class UserController { @Autowired private UserRepository userRepository; private final Logger log = LoggerFactory.getLogger(UserController.class); @GetMapping("/{id}") public User findById(@PathVariable int id){ Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); org.springframework.security.core.userdetails.User principal = (org.springframework.security.core.userdetails.User) authentication.getPrincipal(); Collection authorities = authentication.getAuthorities(); log.info("當前的使用者是{},角色是{}",principal.getUsername(),authorities.stream() .map((GrantedAuthority e) -> e.getAuthority()).collect(Collectors.joining(","))); User user = userRepository.findOne(id); return user; }}
 com.linyuan.controller.UserController : 當前的使用者是user,角色是ROLE_USER com.linyuan.controller.UserController : 當前的使用者是admin,角色是ROLE_ADMIN

修改服務消費者

  • 去掉介面 UserFeignClient 上的 @FeignClient 註解,去掉啟動類上的 @EnableFeignClients 註解

  • 修改 Controller,通過 @Import 導 FeignClientsConfiguration,FeignClientsConfiguration 是 Spring Cloud 為 Feign 提供的預設配置,這裏 userFeignClient 登入賬號是 user,adminFeignClient 登入賬號是 admin,它們使用的是同一個介面

@Import(FeignClientsConfiguration.class)@RestControllerpublic class MovieController {private UserFeignClient adminFeignClient; private UserFeignClient userFeignClient; @Autowired public MovieController(Decoder decoder, Encoder encoder, Client client, Contract contract) { this.userFeignClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("user","password1")) .target(UserFeignClient.class,"http://film-user/"); this.adminFeignClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("admin","password2")) .target(UserFeignClient.class,"http://film-user/"); } @GetMapping("/user/{id}") public UserEntity findByIdUser(@PathVariable int id){ return userFeignClient.findById(id); } @GetMapping("/admin/{id}") public UserEntity findByIdAdmin(@PathVariable int id){ return adminFeignClient.findById(id); }}
  • 測試:

    com.linyuan.controller.UserController : 當前的使用者是user,角色是ROLE_USERcom.linyuan.controller.UserController : 當前的使用者是admin,角色是ROLE_ADMIN
    • 啟動 Eureka Server、film-user、film-consumer

    • 訪問 http://localhost:8010/user/1 與 http://localhost:8010/admin/1 可看到控制檯輸出不同結果

Feign 對壓縮的支援

feign.compression.request.enabled = truefeign.compression.response.enabled = true
feign.compression.request.enabled = truefeign.compression.request.mine-types = text/xml,application/xml,application/json #預設配置feign.compression.request.min-request-size = 2048 #預設配置

Feign 日誌

  • Feign 對日誌的處理非常靈活,可為每個 Feign 客戶端指定日誌策略,每個 Feign 客戶端都會建立一個 Logger,預設名稱為 Feign 介面的完整類名,但 Feign 日誌列印只會對 DEBUG 級別做出響應

  • 我們可為每個 Feign 客戶端配置各自的 Logger.level 物件,告訴 Feign 記錄哪些日誌,Logger.Level 的值有以下選擇:

    • NONE:不記錄任何日誌(預設)

    • BASIC:僅記錄請求方法、URL、響應狀態碼以及執行時間

    • HEADERS:記錄 BASIC 級別的基礎上,記錄請求和響應的 header

    • FULL:記錄請求響應的 header、body 和後設資料

  • 編寫 Feign 配置類

@Configurationpublic class FeignConfiguration { @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.BASIC; }}
@FeignClient(name = "film-user",configuration = FeignConfiguration.class)public interface UserFeignClient { @RequestMapping(value = "/{id}", method = RequestMethod.GET) UserEntity findById(@PathVariable("id") int id);}
logging: level:  com.linyuan.request.UserFeignClient: DEBUG #Feign的Logger.Level只對DEBUG作出響應/
2017-12-22 11:41:34.387 DEBUG 7405 --- [nio-8010-exec-3] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] ---> GET http://flim-user/1 HTTP/1.12017-12-22 11:41:34.395 DEBUG 7405 --- [nio-8010-exec-3] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] <--- HTTP/1.1 200 (8ms)2017-12-22 11:41:35.001 DEBUG 7405 --- [nio-8010-exec-5] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] ---> GET http://flim-user/1 HTTP/1.12017-12-22 11:41:35.012 DEBUG 7405 --- [nio-8010-exec-5] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] <--- HTTP/1.1 200 (10ms)2017-12-22 11:41:35.591 DEBUG 7405 --- [nio-8010-exec-4] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] ---> GET http://flim-user/1 HTTP/1.12017-12-22 11:41:35.602 DEBUG 7405 --- [nio-8010-exec-4] com.linyuan.request.UserFeignClient : [UserFeignClient#findById] <--- HTTP/1.1 200 (11ms)

Feign 構造多引數請求

GET 請求多引數

  • 假設請求 URL 包含多個引數,如:http://flim-user/get?id=1&username=張三,因為 Feign 支援 SpringMVC 註解,則寫法可以為:

    @FeignClient(name = "film-user")public interface UserFeignClient { @RequestMapping(value = "/get", method = RequestMethod.GET) UserEntity get1(@RequestParam("id") int id,@RequestParam("username")String username);}
    @RequestMapping(value = "/get", method = RequestMethod.GET)User get2(@RequestParam Map map);
    public User get(String username,String password){ HashMap map = Maps.newHashMap(); map.put("id",1); map.put("username","張三"); return this.userUserFeignClient.get2(map);}

POST 請求多引數

@RestControllerpublic class UserController{ @PostMapping("/post") public User post (@RequestBody User user){ ... }}
@FeignClient(name = "flim-user")public interface UserFeignClient { @RequestMapping(value = "/post", method = RequestMethod.POST) UserEntity post(@RequestBody User user);}
如有侵權請來信告知:酷播亮新聞 » Sprig Cloud(五):Feign