目录
2.4修改OrderServiceImpl.java的远程调用方法
扫描二维码关注公众号,回复:
14784155 查看本文章
1.什么是Feign
Feign是
Spring Cloud
提供的⼀个声明式的伪
Http
客户端, 它使得调⽤远程服务就像调⽤本地服务
⼀样简单, 只需要创建⼀个接⼝并添加⼀个注解即可。
Nacos很好的兼容了
Feign
,
Feign
默认集成了
Ribbon
, 所以在
Nacos
下使⽤
Fegin
默认就实现了负
载均衡的效果。
2 订单微服务集成Feign
先来看我们以前利用RestTemplate发起远程调用的代码:
/**
* Created by mxin5
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServer {
public static void main(String[] args) {
SpringApplication.run(OrderServer.class,args);
}
/**
* 远程调用通过resttemplate进行调用,直接进行bean的注入,那个业务需要直接autowired进行注入
* @LoadBalanced就可以实现负载均衡,原理就是一个标记,标记Resttemplate发出的请求要被我们的Ribbon进行拦截和处理
* */
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
String url = "http://product-service/product/"+productId;
Product product = restTemplate.getForObject(url,Product.class);
存在下面的问题:
-
代码可读性差,编程体验不统一
-
参数复杂URL难以维护
所以就采用feign来代替RestTemplate,采用接口的方式进行远程调用和负载均衡。
Fegin的使用步骤如下:
2.1.引入依赖
在shop-order-server项⽬的pom⽂件加⼊Fegin的依赖
<!--fegin组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2添加注解
在启动类OrderServer.java上添加Fegin的扫描注解,注意扫描路径(默认扫描当前包及其⼦包)
/**
* Created by mxin5
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServer {
public static void main(String[] args) {
SpringApplication.run(OrderServer.class,args);
}
/**
* 远程调用通过resttemplate进行调用,直接进行bean的注入,那个业务需要直接autowired进行注入
* @LoadBalanced就可以实现负载均衡,原理就是一个标记,标记Resttemplate发出的请求要被我们的Ribbon进行拦截和处理
* */
// @LoadBalanced
// @Bean
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
}
2.3编写Feign的客户端
在shop-order-server项⽬中新增接⼝ProductFeignApi
/**
* Created by mxin5
* name的名称一定要和订单服务的服务名保持一致,fallback表示调用失败时的兜底策略
* 谁是主调用者谁就集成feign
*/
@FeignClient(name = "product-service")
public interface ProductFeignApi {
//跟product-service中的controller的接口一致
@GetMapping("/product/{pid}")
public Product findByPid(@PathVariable("pid") Long pid);
}
@GetMapping("/product/{pid}")
public Product findByPid(@PathVariable("pid") Long pid) {
...
}
这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
服务名称:product-service
请求方式:GET
请求路径:/product/{pid}
请求参数:Long pid
返回值类型:Product
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。
2.4修改OrderServiceImpl.java的远程调用方法
package cn.wolfcode.service.impl;
import cn.wolfcode.dao.OrderDao;
import cn.wolfcode.domain.Order;
import cn.wolfcode.domain.Product;
import cn.wolfcode.feign.ProductFeignApi;
import cn.wolfcode.service.OrderService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j //日志
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductFeignApi productFeignApi;
//以前的远程调用的方式
// @Autowired
// private RestTemplate restTemplate;
@Override
public Order createOrder(Long productId, Long userId) {
log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", productId);
/**
* 以前的方式通过Resttemplate进行调用
* 问题:1端口号和服务器修改了又要重新进行修改和重启
* 2使用集群的方式的话要实现负载均衡,要不断的进行修改,服务器上下线无法感知
* 这样就可以使用Springcloud的负载均衡组件feign和注册中心组件nacos
* */
// String url = "http://localhost:8081/product/"+productId;
// String url = "http://product-service/product/"+productId; //ribbon实现远程调用和负载均衡
//直接传入地址和实体类字节码文件(转成什么对象)进行获取
// Product product = restTemplate.getForObject(url,Product.class);
/** 远程调用商品微服务,查询商品信息,通过feign进行调用,并采用负载均衡的方式
openfeign直接省略了在启动类进行注入resttemplate的bean,直接调用的时候会
将携带服务名去获取本地缓存的服务列表,然后采用轮询或其他负载均衡算法去选择一个可用的服务进行调用*/
Product product = productFeignApi.findByPid(productId);
log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));
//创建订单并保存
Order order = new Order();
order.setUid(userId);
order.setUsername("mxin5");
order.setPid(productId);
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderDao.save(order);
log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
return order;
}
}
2.5重启订单服务,并验证
SpringCloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理(所以我们并不需要编写接口实现类),并注册到Spring容器中。
3.Feign远程调用的工作原理
注意:服务提供者和服务调用者的写法
1.服务提供者
//服务提供者
@RestController
public class ProductController{
@GetMapping("/product/{pid}")
public Product findByPid(@PathVariable("pid") Long pid) {
...
}
}
2.服务调用者(注意接口中的参数必须要用注解@PathVariable或者@RequestParam等注解通过反射拿到参数)
@FeignClient(name = "product-service",fallback = ProductFeignFallBack.class)
public interface ProductFeignApi {
//跟product-service中的controller的接口一致
@GetMapping("/product/{pid}")
public Product findByPid(@PathVariable("pid") Long pid);
}
总结
使用Feign的步骤:
① 引入依赖
② 添加@EnableFeignClients注解
③ 编写FeignClient接口
④ 使用FeignClient中定义的方法代替RestTemplate