一、实现目标
module[user-service]和modul[order-service]由RestTemplate通信改成用OpenFeign通信
OpenFeign官网使用文档
二、Spring Cloud OpenFeign简介
Spring Cloud OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
三、项目[ac-mall-cloud]接入OpenFeign
3.1 父级工程配置
在父级工程 [ac-mall-cloud] pom.xml中引入OpenFeign依赖
org.springframework.cloud
spring-cloud-starter-openfeign
${alibaba.cloud.version}
父级工程 [ac-mall-cloud] pom.xml全配置如下
4.0.0
org.example
ac-mall-cloud
1.0-SNAPSHOT
user-service
product-service
order-service
pom
1.8
Greenwich.SR1
8.0.17
3.2.0
1.1.10
2.2.4.RELEASE
2.1.0.RELEASE
1.18.10
org.springframework.boot
spring-boot-starter-parent
${boot.version}
pom
import
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${alibaba.cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
${alibaba.cloud.version}
org.springframework.cloud
spring-cloud-starter-openfeign
${alibaba.cloud.version}
com.baomidou
mybatis-plus-boot-starter
${mybatis.plus.version}
com.alibaba
druid-spring-boot-starter
${druid.version}
mysql
mysql-connector-java
${mysql.version}
org.projectlombok
lombok
${lombok.version}
provided
org.projectlombok
lombok
1.18.10
provided
org.springframework.boot
spring-boot-maven-plugin
3.2 module [user-service] 配置
1、新建一个constant包放常量类,并新建ModulePrePath类
public class ModulePrePath {
public static final String API = "api";
}
2、新建一个api包,放供其他微服务调用接口的类,并新建UserApi类
/**
* @author Alan Chen
* @description 用户API
* @date 2021/3/31
*/
@RestController
@RequestMapping(ModulePrePath.API+"/users")
public class UserApi {
@Autowired
IUserService userService;
@GetMapping("/{userId}")
public User getUser(@PathVariable String userId){
return userService.getUser(userId);
}
}
module [user-service] 效果如下
3、测试UserApi接口
重启module [user-service] ,在浏览器中输入访问地址http://127.0.0.1:8010/api/users/1
,效果如下
4、api包和controller包说明
controller包里放的是供本项目前端客户端(如APP)访问的接口;api包里的接口,是专门提供给其他微服务访问的。
3.3 module [order-service] 配置
1、在module [order-service]pom.xml中引入OpenFeign依赖
org.springframework.cloud
spring-cloud-starter-openfeign
module [order-service]pom.xml全配置如下
ac-mall-cloud
org.example
1.0-SNAPSHOT
4.0.0
org.ac
order-service
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
2、主启动类加上注解@EnableFeignClients注解
@EnableFeignClients
申明该项目是Feign客户端,扫描对应的feign client
@EnableFeignClients
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
@Bean
@LoadBalanced // Ribbon负载均衡注解
RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3、新建一个constant包放常量类,并新建ModulePrePath类
public class ModulePrePath {
public static final String API = "api";
}
4、新建一个feign包放feign接口,并新建UserServiceClient接口
@FeignClient("user-service")
public interface UserServiceClient {
/**
* 获取用户信息
* @param userId
* @return
*/
@GetMapping(ModulePrePath.API+"/users/{userId}")
UserDto getUser(@PathVariable("userId") String userId);
}
@FeignClient("user-service")
配置的是module[user-service]的服务名
@GetMapping(ModulePrePath.API+"/users/{userId}")
路径和module[user-service]中UserApi获取用户信息接口的路径是一致的。
5、将RestTemplate通信改成用OpenFeign通信
修改OrderServiceImpl类的makeOrder方法
// 1、根据用户ID调用用户服务接口数据,查询用户的名字
//UserDto userDto = restTemplate.getForObject(USER_SERVICE_URL,UserDto.class,userId);
//换成OpenFeign
UserDto userDto = userServiceClient.getUser(userId);
OrderServiceImpl全部代码如下
@Service
public class OrderServiceImpl implements IOrderService {
@Autowired
OrderDao orderDao;
@Autowired
RestTemplate restTemplate;
@Autowired
UserServiceClient userServiceClient;order-service
//final static String USER_SERVICE_URL="http://127.0.0.1:8010/users/{userId}";
final static String USER_SERVICE_URL="http://user-service/users/{userId}"; //用服务名来替换IP
public Order makeOrder(String productId, String userId) {
/**
* RestTemplate是java创造出来的,在java能够访问到网络资源的包是java.net.URLConnenction/Socket
* RestTemplate是对URLConnenction的封装
* apache--HttpClient 也是对URLConnenction/HttpURLConnenction的封装
* oKHttp 也封装了URLConnenction
* netty/rpc/grpc/thirt/tomcat
*/
// 1、根据用户ID调用用户服务接口数据,查询用户的名字
//UserDto userDto = restTemplate.getForObject(USER_SERVICE_URL,UserDto.class,userId);
//换成OpenFeign
UserDto userDto = userServiceClient.getUser(userId);
String userName=userDto.getUserName();
// 2、生成订单
Order order = new Order();
order.setId(UUID.randomUUID().toString());
order.setCreateTime(new Date());
order.setPriceFen(1600L);
order.setUserId(userId);
order.setUserName(userName);
order.setProductId(productId);
order.setOrderNo(UUID.randomUUID().toString());
// 3、保存数据库
orderDao.insert(order);
return order;
}
}
6、测试下单接口
我们在浏览器中输入访问地址http://127.0.0.1:8020/orders/1/1
,效果如下
四、Ribbon、Feign、LoadBalancer和OpenFeign的关系
4.1 Ribbon
- Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
- Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
- Ribbon的使用需要代码里手动调用目标服务
- RestTemplate集成 Ribbon,可以让RestTemplate通过服务名来访问微服务接口(否则只能通过IP访问)
4.2 Feign
- Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端
- Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
- Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
- Feign本身不支持Spring MVC的注解,它有一套自己的注解。
4.3 OpenFeign
- OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如
@RequesMapping
等等。 - OpenFeign的
@FeignClient
可以解析SpringMVC的@RequestMapping
注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
4.4 LoadBalancer
Ribbon目前已经停止维护,新版SpringCloud(2021.x.x)用LoadBalancer替代了Ribbon。Spring Cloud全家桶在Spring Cloud Commons项目中,添加了Spring cloud Loadbalancer作为新的负载均衡器,并且做了兼容
Nacos 2021版本已经没有自带ribbon的整合,所以无法通过修改Ribbon负载均衡的模式来实现nacos提供的负载均衡模式,需要引入另一个支持的jar包loadbalancer。
4.5 Ribbon/LoadBalancer载均衡策略
Ribbon有多种负载均衡策略
- 随机 RandomRule
- 轮询 RoundRobinRule
- 重试 RetryRule
- 最低并发 BestAvailableRule
- 可用过滤 AvailabilityFilteringRule
- 响应时间加权重 ResponseTimeWeightedRule
- 区域权重 ZoneAvoidanceRule
LoadBalancer貌似只提供了两种负载均衡器,不指定的时候默认用的是轮询
- RandomLoadBalancer 随机
- RoundRobinLoadBalancer 轮询
五、附录
项目源码地址