一、feign使用
1、集成方法
1.1、pom
consumer添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.6.RELEASE</version></dependency>
1.2、启动类
consumer启动类加上@EnableFeignClients注解,即开启feign;
1.3、consumer调用provider:
编写一个中间service,consumer调用service,service调用provider。这个service类头加@FeignClient注解:
@FeignClient(value = "my-service",path = "/myProvider")
FeignClient的几个属性:
(1)value:provider配置文件中的spring.application.name,
注意这里的value值不分大小写,my-service和MY-SERVICE都可以。
(2)name:name和value这两个属性的作用是一样的,如果没有配置url,那么配置的值将作为服务的名称,用于服务的发现,反之只是一个名称。
(3)path:如果provider在配置文件里面配置了server.context-path,FeignClient就需要指明path。
(4)url:属性一般用于调试程序,允许我们手动指定@FeignClient调用的地址。
@FeignClient(value = "goods-service", url="http://127.0.0.1:7001")
public interface GoodsService
{@GetMapping("/goods/list")String getGoodsList();
}
2、调用方法
上面提到的service,关于service调用provider传参的问题:
2.1、无参调用
post、get请求都可以
2.2、非对象参数
如Integer、String等,适用于get请求。
service方法上需要加@RequestParam注解,且括号中一定要有值(参数的别名)和被调用方provider的参数名保持一致,被调用方可加@RequestParam也可不加;
2.3、对象参数
javaBean,map,list等,只适用于post请求。
被调用方provider加@RequestBody注解,调用方service的方法可加可不加;
2.4、header头部参数:
provider和service方法上都使用@RequestHeader注解,且value指明参数别名。
二、集成demo
1、初版
1.1、父pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.demo.nacos</groupId><artifactId>nacos-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>nacos-demo</name><packaging>pom</packaging><!-- springBoot --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.4.RELEASE</version></parent><!-- 模块说明:这里声明多个子模块 --><modules><module>provider</module><module>consumer</module><module>nacos-common</module></modules><!-- 版本说明:这里统一管理依赖的版本号 --><dependencyManagement><dependencies><!-- SpringCloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Finchley.RELEASE</version></dependency><!-- SpringCloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.0.RELEASE</version></dependency><!--服务注册--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>0.2.2.RELEASE</version></dependency><!-- nacos 注册中心客户端 --><!-- <dependency>--><!-- <groupId>com.alibaba.cloud</groupId>--><!-- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>--><!-- <version>2.1.0.RELEASE</version>--><!-- </dependency>--><!--集中配置--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2.1.0.RELEASE</version></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--nocas必须在web环境下--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
1.2、provider:
(1)pom:
<parent><artifactId>nacos-demo</artifactId><groupId>com.demo.nacos</groupId><version>0.0.1-SNAPSHOT</version></parent><dependencies><dependency><groupId>com.demo.nacos</groupId><artifactId>nacos-common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- SpringCloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId></dependency><!-- SpringCloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId></dependency><!--服务注册--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--集中配置--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency></dependencies>
(2)bootstrap:
spring:application:name: my-servicecloud:compatibility-verifier:enabled: falsenacos:#服务注册discovery:server-addr: xxx.xx.xxx:8848#配置中心config:server-addr: xxx.xx.xxx:8848group: wtyyprofiles:active: prod
server:port: 1111servlet:context-path: /myProvider
(3)启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}
}
(4)controller接口
import com.demo.nacos.common.dto.UserDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;@RestController
@RequestMapping("/configTest")
//刷新配置
@RefreshScope
public class ProviderTestController {@Value("${user.text}")private String userText;private static Logger logger = LoggerFactory.getLogger(ProviderTestController.class);/*** 1、无参 无返回* @param request* @return* @throws InterruptedException*/@GetMapping("/hanNoParam")public void getUserText(HttpServletRequest request) throws InterruptedException {logger.info("调用无参接口");}/*** 2、有参* @return* @throws InterruptedException*/@GetMapping("/hanParams")public String hanParams(String userName) throws InterruptedException {logger.info("调用有参接口");return userName+":"+userText;}/*** 3、有参,对象参数* @return* @throws InterruptedException*/@PostMapping("/hanObjParams")public UserDTO hanObjParams(@RequestBody UserDTO userDTO) throws InterruptedException {logger.info("调用对象参数接口");return userDTO;}/*** 4、参数加header* @return* @throws InterruptedException*/@PostMapping("/hanParamsAndHeader")public String hanParamsAndHeader(@RequestBody UserDTO userDTO,@RequestHeader("token") String token) throws InterruptedException {logger.info("调用参数和header接口");return userDTO.getUserName()+"的token:"+token;}
}
1.3、consumer:
(1)pom:
<parent><artifactId>nacos-demo</artifactId><groupId>com.demo.nacos</groupId><version>0.0.1-SNAPSHOT</version></parent><dependencies><dependency><groupId>com.demo.nacos</groupId><artifactId>nacos-common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- SpringCloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId></dependency><!-- SpringCloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId></dependency><!--服务注册--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--集中配置--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.6.RELEASE</version></dependency></dependencies>
(2) bootstrap:
spring:application:name: my-consumercloud:compatibility-verifier:enabled: falsenacos:#服务注册discovery:server-addr: xxx.xx.xxx:8848#配置中心config:server-addr: xxx.xx.xxx:8848group: wtyy
server:port: 2222servlet:context-path: /myConsumer
(3) 启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
}
(4) service:重点
import com.demo.nacos.common.dto.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(value = "my-service",path = "/myProvider")
public interface NacosConfigTestService {@RequestMapping("/configTest/hanNoParam")void hanNoParam();@RequestMapping("/configTest/hanParams")String hanParams(@RequestParam("userName")String userName);@RequestMapping("/configTest/hanObjParams")UserDTO hanObjParams(@RequestBody UserDTO userDTO);@RequestMapping("/configTest/hanParamsAndHeader")String hanParamsAndHeader(@RequestBody UserDTO userDTO,@RequestHeader("token") String token);
}
(5) controler:
import com.demo.nacos.common.dto.UserDTO;
import com.demo.nacos.consumer.service.NacosConfigTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;@RestController
@RequestMapping("/consumerTest")
public class ConsumerTestController {@Autowiredprivate NacosConfigTestService nacosConfigTestService;@GetMapping("/hanNoParam")public void getTemp(HttpServletRequest request) throws InterruptedException {nacosConfigTestService.hanNoParam();}@GetMapping("/hanParams")public String hanParams(String userName) throws InterruptedException {return nacosConfigTestService.hanParams(userName);}@PostMapping("/hanObjParams")public UserDTO hanObjParams(@RequestBody UserDTO userDTO) throws InterruptedException {return nacosConfigTestService.hanObjParams(userDTO);}@PostMapping("/hanParamsAndHeader")public String hanParamsAndHeader(@RequestBody UserDTO userDTO,HttpServletRequest request) throws InterruptedException {String token = request.getHeader("token");return nacosConfigTestService.hanParamsAndHeader(userDTO,token);}
}
1.4、测试
分别启动provider、consumer,可以看到都注册到nacos上了:
(1)非对象参数
(2)对象参数
(3)对象参数&header
2、feign负载均衡
将provider配置文件修改为1112再启动一次,可以看到nacos上provider有两个节点:
2.1、默认轮询:
下面调用多次http://localhost:2222/myConsumer/consumerTest/hanNoParam接口,可以看到两个provider轮询调用:
这是因为nacos上两个节点的权重默认都是一样的:
2.2、自定义权重:
下面将1111节点权重设置为2,1112节点设置为0:
再次请求接口,从控制台日志可以看到都打到1111节点上了。
2.3、下线:
(1)这时点击1111节点的下线:
因为在线上的1112节点权重为0(等于下线),所以请求接口报错:
(2)而将1112节点权重改为1,这时相当于1111下线了,线上是1112这个单节点
再次请求接口,请求都走到1112节点了
(3)点击1111节点的上线按钮,恢复双节点:
多次请求接口,可以看到两个节点都有访问。
3、feign的继承特性
上面的代码有很多重复的地方,下面利用feign的继承特性进行封装。
(1)公共代码封装
把公共代码封装成接口,放到commom组件中
package com.demo.nacos.common.api;import com.demo.nacos.common.dto.UserDTO;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;@RequestMapping("/configTest")
public interface CommonTestService {/*** 1、无参 无返回* @return* @throws InterruptedException*/@RequestMapping("/hanNoParam")void hanNoParam();/*** 2、有参* @return* @throws InterruptedException*/@RequestMapping("/hanParams")String hanParams(@RequestParam("userName")String userName);/*** 3、有参,对象参数* @return* @throws InterruptedException*/@RequestMapping("/hanObjParams")UserDTO hanObjParams(@RequestBody UserDTO userDTO);/*** 4、参数加header* @return* @throws InterruptedException*/@RequestMapping("/hanParamsAndHeader")String hanParamsAndHeader(@RequestBody UserDTO userDTO,@RequestHeader("token") String token);
}
(2)provider生产者controller接口改造:
实现公共接口并覆写方法即可
package com.demo.nacos.provider.controller;import com.demo.nacos.common.api.CommonTestService;
import com.demo.nacos.common.dto.UserDTO;
import com.demo.nacos.provider.mapper.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.util.List;@RestController
//刷新配置
@RefreshScope
public class ProviderTestController implements CommonTestService {@Value("${user.text}")private String userText;private static Logger logger = LoggerFactory.getLogger(ProviderTestController.class);@Autowiredprivate UserDao userDao;@RequestMapping("/getAllUsers")public List<UserDTO> getAllUsers(){return userDao.getAllUsers();}/*** 1、无参 无返回* @return* @throws InterruptedException*/@Overridepublic void hanNoParam() {logger.info("调用无参接口");}/*** 2、有参* @return* @throws InterruptedException*/@Overridepublic String hanParams(String userName) {logger.info("调用有参接口");return userName+":"+userText;}/*** 3、有参,对象参数* @return* @throws InterruptedException*/@Overridepublic UserDTO hanObjParams(@RequestBody UserDTO userDTO) {logger.info("调用对象参数接口");return userDTO;}/*** 4、参数加header* @return* @throws InterruptedException*/@Overridepublic String hanParamsAndHeader(@RequestBody UserDTO userDTO,@RequestHeader("token") String token) {logger.info("调用参数和header接口");return userDTO.getUserName()+"的token:"+token;}
}
(3)feign调用
继承即可
package com.demo.nacos.consumer.service;import com.demo.nacos.common.api.CommonTestService;
import com.demo.nacos.common.dto.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(value = "my-service",path = "/myProvider")
public interface NacosConfigTestService extends CommonTestService {}
(4)测试:
所有接口调用正常
无参:
普通参数:
对象参数&header: