上次我们写到spring cloud的服务治理Eureka(如果还未了解spring cloud eureka的请跳转到spring cloud之Eureka--服务治理, 将一个项目的各个模块给分开, 单独分离成一个项目进行开发, 使各功能各家独立; 然后将所有项目注册到Eureka服务中, 进行统一管理;
我们现在已经达到了服务的统一管理, 那么我们该如果调用各个模块呢 ? 有的人肯定会说, java进行网络请求啊URL 然后设置请求头, 设置参数, 拿到请求地址, 发送请求, 取到返回参数,进行处理, 巴拉巴拉一大堆.....;觉得麻烦又封装了一个请求的工具类, 看似好像简单了许多但是又没考虑到你发送的请求地址怎么处理?写死? 我们可是java高级工程师鸭~ 怎么可能进行硬编码鸭, 下面就进行如何优雅的进行服务之间的相互访问;
下面是我github的一个demo仅供参考,后续我会将spring cloud的内容继续完善;
spring_cloud_demo
叨叨了那么多, 下面进入正题;
1.Feign
Feign, 官方的话我就不说了, 具体大家去官网看; 在使用中, 无非是封装了一个发送网络请求的一个工具, 但是他跟Eureka搭配使用起来就可以动态的调用Eureka服务上的某个服务, 只要指定服务的ID和需要调用的接口; 这里注意下, 仅支持RESTful风格的请求;
这么说, 肯定还是迷糊, 下面我们看看如何去使用Feign
1.1添加Fegin依赖
该依赖在spring cloud 基础上添加,如果还不会请看我之前的一篇文章spring cloud之Eureka--服务治理;
<!--添加feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
1.2添加启动注解
spring boot启动类上添加注解: @EnableFeignClients
package cn.cooplan.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@EnableFeignClients //开启Feign
@EnableEurekaClient //开启Eureka客户端服务
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
1.3编写Feign接口
这里我们编写Feign的接口, 当spring boot扫描掉@FeignClient注解时, 会为该接口生成代理类;
package cn.cooplan.order.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.Goods;
/**
* 订单使用, 用来feign调用goods服务
* @Author MaoLG
* @Date 2018/12/8 10:53
*/
//@FeignClient 注解, 注解中的参数为调用Eureka中的服务的名称(ID)
@FeignClient("goods") //请求Eureka中的服务中goods服务
public interface GoodsFeignClient {
//该请求方式只支持 RESTful请求方式,
//此处的 @RequestMapping为springmvc的注解, 借用该注解模仿请求,此处不是controller,请不要搞混
@RequestMapping("/goods/getGoodsById/{goodsId}")
//@RequestLine("POST /goods/getGoodsById/{goodsId}")//Feign自己的注解与@RequestMapping效果一样
public Goods getGoodsById(@RequestParam("goodsId") Integer goodsId);
//多个参数
(@RequestParam Map<Stirng, Object> param);
}
@FeignClient注解参数的由来,该参数可以在yml文件中自己制定,不指定Eureka会给一个默认值
Feign.jpg
如何设置服务名称:这里不区分大小写
设置服务名称.jpg
1.4调用接口
package cn.cooplan.order.service.impl;
import cn.cooplan.order.feign.GoodsFeignClient;
import cn.cooplan.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import dao.OrderDao;
import dao.OrderGoodsDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import pojo.Goods;
import pojo.Order;
import pojo.OrderGoods;
import java.util.ArrayList;
import java.util.List;
/**
* @Author MaoLG
* @Date 2018/12/7 14:03
*/
@Service
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private OrderGoodsDao orderGoodsDao;
//注入上步编写的Feign接口
@Autowired
private GoodsFeignClient goodsFeignClient;
@Override
public List<Goods> getOrderInGoods(Integer orderId) {
OrderGoods o = new OrderGoods();
o.setOrderId(orderId);
QueryWrapper queryWrapper = new QueryWrapper(o);
List<OrderGoods> ogs = orderGoodsDao.selectList(queryWrapper);
List<Goods> goodses = new ArrayList<>();
for (OrderGoods og: ogs) {
/*上面为我自己的业务, 下面这行代码才是调用刚才编写的Feign接口
* 只要在Feign接口指定好访问的服务和访问URL, 参数写好就行了, 注意只支持RESTful请求风格
* 如果传递多个参数的话, 可以使用Map接收
*/
Goods goods = goodsFeignClient.getGoodsById(og.getGoodsId());
goodses.add(goods);
}
return goodses;
}
1.5效果展示
order服务中的controller
package cn.cooplan.order.controller;
import cn.cooplan.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author MaoLG
* @Date 2018/12/7 14:00
*/
@RestController
@RequestMapping("/order/")
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("getOrderInGoods")
public Object getOrderInGoods(Integer orderId){
return orderService.getOrderInGoods(orderId);
}
}
调取结果
结果.jpg
如果你返回的最后结果是XML形式, 在你的pom.xml中的Eureka依赖中添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<!--去除返回xml数据, 去掉后改为json数据-->
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
去除xml的依赖, 这个地方是默认返回xml, 我们使用json比较方便;
2.总结
Feign的基础用法就是如此, 我个人认为该框架由spring cloud整合进来, 进行了优化, 兼容了springmvc使我们在spring的大环境的背景下减少了我们学习成本, 让我们更加注重于自己业务的开发, 减少了大量重复代码,使我们的代码更有灵活性;(Feign还有负载均衡的效果, 不过后面我会专门介绍一个负载均衡实现的spring cloud中的组件)
下次我会介绍关于,如果我们的一个服务挂掉了,如何不影响其他项目,避免雪崩效应,并进行一些适当的处理;
下面是我github的一个demo仅供参考,后续我会将spring cloud的内容继续完善;
spring_cloud_demo