SpringCloud+SpringBoot 项目搭建 (五) Feign
本篇文章接上一篇:SpringCloud+SpringBoot 项目搭建 (四) RockerMq
SpringCloud+SpringBoot 项目搭建 (五) Feign
1.简介
Feign:是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单,它的使用方法就是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。
2.使用 feign
使用之前先学习下feignClient的注解
- name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
- url: url一般用于调试,可以手动指定@FeignClient调用的地址
- decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
- configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
- fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
- fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
- path: 定义当前FeignClient的统一前缀
引用maven和配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
在core里面编写一个最基本的feign配置信息
@Configuration
public class FeignConfiguration {
@Bean
public Contract feignContract() {
return new SpringMvcContract();
}
}
创建一个feignClient
@FeignClient(value = "productcenter",configuration = FeignConfiguration.class,fallback = ProductSearchFeignResilience.class)
public interface ProductSearchFeigApi {
@RequestMapping("/api/product/searchProductId")
public ApiResponse<ProductDto> searchId(@RequestParam("productId") String id);
}
创建feignClient实现方法
@RefreshScope
@RestController
public class ProductSearchFignClient implements ProductSearchFeigApi {
@Resource
ProductService productService;//商品模块中自己的服务
@Override
public ApiResponse<ProductDto> searchId(@RequestParam("productId") String id) {
Product product = productService.getById(id);
ProductDto productDto = null;
if (product!=null) {
productDto = new ProductDto();
BeanUtils.copyProperties(product, productDto);
}
return ApiResponse.success(productDto);
}
}
调用方法
@Log4j2
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Resource
OrderMapper orderMapper;
@Resource
private DefaultMQProducer defaultMQProducer;
@Resource
private ProductService productService;
@Override
@Transactional(rollbackFor = Exception.class)
public Order create(String productId,Integer number, Long userId) {
//创建订单
// TODO ... 参考上一期代码
//扣除商品库存
this.reduceProductStock(productId,number);
//模拟发送短信
//TODO ... 参考上一期代码
return insert>0?order:null;
}
private void reduceProductStock(String productId, Integer number){
ProductDto productDto = productService.searchId(productId);
productDto.setChangeStock(0-number);
productService.updateProductStockById(productDto);
}
}
@Log4j2
@Service
public class ProductServiceImpl implements ProductService {
@Resource
ProductSearchFeignApi productSearchFeignApi;//调用core里面的feignClient
@Override
public int updateProductStockById(ProductDto productDto) {
return 0;
}
@Override
public ProductDto searchId(String productId) {
ApiResponse<ProductDto> apiResponse = productSearchFeignApi.searchId(productId);
if(apiResponse==null){
throw new MyProductServiceBusinessException("获取商品信息失败!");
}
if (apiResponse.error()) {
throw new MyProductServiceBusinessException("服务器内部错误", productId);
}
return apiResponse.getResult();
}
}
添加启动注解
/**订单模块*/
@MapperScan("com.dongyue.ordercenter.mapper")
@SpringBootApplication
@EnableEurekaClient
@ComponentScan(basePackages={"com.dongyue"})
@EnableFeignClients(basePackages = "com.dongyue")
public class OrdercenterApplication {
public static void main(String[] args) {
SpringApplication.run(OrdercenterApplication.class, args);
}
}
/**商品模块*/
@SpringBootApplication
@ComponentScan(basePackages={"com.dongyue"})
@EnableFeignClients(basePackages = {"com.dongyue"})
@EnableEurekaClient
@MapperScan("com.dongyue.productcenter.mapper")
public class ProductcenterApplication {
public static void main(String[] args) {
SpringApplication.run(ProductcenterApplication.class, args);
}
}
- 坑点1 FeignClient中value里面的值一定要与要访问模块中在中心注册中的名称一样或者配置url
- 坑点2 FeignClient创建的参数信息一定要与实现方法中的参数信息一致
- 坑点3 如果跟启动没有在同一个包名下面,扫描需要添加路径,否则找不到资源
- 坑点4 如果有可能出现服务被多次消费的情况别忘记加上配置:spring.main.allow-bean-definition-overriding=true
至此一个最基本的feign就集成完毕