簡介
快速入門
restTemplate.getForObject("http://flim-user/"+id,User.class);
Mapmap = 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 extends GrantedAuthority> 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);}