feign 作为一个声明式的 Http Client 开源项目。在微服务领域,相比于传统的 apache httpclient 与在 spring 中较为活跃的 RestTemplate 更面向服务化,更易于使用。底层封装了 Jersey 与 CXF 分别用于 REsT 与 SOAP 的服务(对应有 JAX-RS 与 JAX-WS API),当然也可以配置换成其它类似的实现,比如 OkHttp 、Ribbon 或者 Apache HC 等。
feign 基本用法及注解的使用看官方文档。下面介绍下 Spring Cloud 中的封装及实现细节(Spring Cloud 文档):
一、 基本用法
现有服务提供方:需要调用它的 createUser 方法
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/current", method = RequestMethod.GET)
public Principal getUser(Principal principal) {
return principal;
}
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(method = RequestMethod.POST)
public void createUser(@Valid @RequestBody User user) {
userService.create(user);
}
}
使用 feign 构建消费服务方,遵循以下步骤:
引入 maven 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
1. 启用:使用 @EnableFeignClients 注解启动 feign 模块基础功能(扫描 feign client包,使用默认或指定的相关配置等等)
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 声明:使用 @FeignClient("app-name") 创建声明式的 HC:很简单配置下 service 名称/url 与 发出请求的路径就好了。
@FeignClient(name = "auth-service")
public interface AuthServiceClient {
@RequestMapping(method = RequestMethod.POST, value = "/users", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void createUser(User user);
}
3. 调用:上面的代码,相对于服务提供方,它是客户端服务消费方。相对于服务消费方自身,它上升到一个 service,因此我们可以在 service 层或 controller 层调用它:
@Service
public class AccountServiceImpl implements AccountService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private AuthServiceClient authClient;
@Autowired
private AccountRepository repository;
/**
* {@inheritDoc}
*/
@Override
public Account create(User user) {
Account existing = repository.findByName(user.getUsername());
Assert.isNull(existing, "account already exists: " + user.getUsername());
// 调用feign HC服务
authClient.createUser(user);
Saving saving = new Saving();
saving.setAmount(new BigDecimal(0));
saving.setCurrency(Currency.getDefault());
saving.setInterest(new BigDecimal(0));
saving.setDeposit(false);
saving.setCapitalization(false);
Account account = new Account();
account.setName(user.getUsername());
account.setLastSeen(new Date());
account.setSaving(saving);
repository.save(account);
log.info("new account has been created: " + account.getName());
return account;
}
...
二、feign 的相关配置(比如日志、hytrix 等)
配置方式有 3种:
1. 使用 JavaConfig 方式
配置类(这里建议不要加 @Configuration 注解,否则将变成全局配置)
public class FileConf {
private final ObjectFactory<HttpMessageConverters> messageConverters;
@Autowired
public FileConf(ObjectFactory<HttpMessageConverters> messageConverters) {
this.messageConverters = messageConverters;
}
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
调用端
@FeignClient(value = "service-thirdparty", configuration = FileConf.class)
@RequestMapping(value = "/storage")
public interface StorageClient {
/**
* 上传图片
*/
@RequestMapping(
value = "/imageUpload",
method = RequestMethod.POST,
consumes = MULTIPART_FORM_DATA_VALUE)
BusinessResult uploadImage(@RequestParam(value = "bucket") String bucket,
@RequestPart(value = "file", required = false) MultipartFile file);
2. 使用 application.yml
# To disable Hystrix in Feign
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
hystrix:
enabled: false
# To set thread isolation to SEMAPHORE
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
logging.level.project.user.UserClient: DEBUG
注意事项:
① 如果 @Configuration的 JavaConfig 与 properties 配置同时存在,那么后者会覆盖前者。通过设定 feign.client.default-to-properties
to false
. 改变优先权。
② 只有开启 DEBUG级别的日志, feign 的log功能才会生效。
③ 如果 classpath 引入了 hytrix(如下),并且配置启用 hytrix(比如 feign.hystrix.enabled=true),那么默认会启用 circuit breaker 。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在 Spring Cloud Dalston 及之后的版本中,circuit breaker 是可选操作。需要使用 @EnableCircuitBreaker 手动开启。
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class Application {
扩展:使用断路器功能
声明:
@FeignClient(name = "statistics-service", fallback = StatisticsServiceClientFallback.class)
public interface StatisticsServiceClient {
@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void updateStatistics(@PathVariable("accountName") String accountName, Account account);
}
定义 hytrix:
@Component
public class StatisticsServiceClientFallback implements StatisticsServiceClient {
private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsServiceClientFallback.class);
@Override
public void updateStatistics(String accountName, Account account) {
LOGGER.error("Error during update statistics for account: {}", accountName);
}
}
233
参考资料
https://github.com/sqshq/PiggyMetrics (完整示例)