Ribbon是一个基于Http和TCP的负载均衡工具,而Feign(音:菲恩)是一个声明式的伪Http客户端,它比Ribbon更加的优雅。Feign使用的是接口的方式。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。
一、Feign使用介绍
1.1 导入feign依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
1.2 编写application.yml配置文件
#指明注册中心的位置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#当前项目部署的端口
server:
port: 8765
#当前项目的名称
spring:
application:
name: service-feign
1.3 编写启动类
@EnableFeignClients注解是开启feign负载均衡工具。
package com.safesoft.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class ApplicationFeign {
public static void main(String[] args) {
SpringApplication.run(ApplicationFeign.class, args);
}
}
1.4 编写服务接口
package com.safesoft.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "SERVICE-CLIENT")
public interface HelloService {
/**
* 从SERVICE-CLIENT服务器的/hi接口获取JSON数据
* @param name
* @return
*/
@RequestMapping("/hi")
String obtainOtherServerJsonData(@RequestParam(value = "name") String name);
}
1.5 编写Controller
package com.safesoft.feign.web;
import com.safesoft.feign.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
/**
* 因为HelloService仅仅使用了@FeiginClient注解
* 没有使用@Bean类型的注解,比如@Service @Component等
* 所以编译器会警告,其实可以忽视它
*/
@Autowired
private HelloService helloService;
@RequestMapping("/sayHello")
public String sayHello(String name) {
return helloService.obtainOtherServerJsonData(name);
}
}
1.6 启动Feign服务器
在浏览器上输入http://localhost:8765/hello?name=pc,尝试从8765端口获取JSON数据。此请求会被Feign服务器负载均衡到部署在8762端口与8763端口的服务器上。
第一次刷新结果如下:
第二次刷新结果如下:
1.7 源码下载地址
二、项目中实际使用
1 admin服务,端口号32032,admin主启动类要加@EnableFeignClients
1.1CmsUserGroupClient
import com.xxx.cms.service.api.api.ICmsUserGroupController;
@FeignClient(value = "${feign.cms.service.name}", contextId = "CmsUserGroupClient")
//@FeignClient(value = "mth-cms-service", contextId = "CmsUserGroupClient")
//@FeignClient(url = "127.0.0.1:32031", value = "mth-equity-service", contextId = "CmsUserGroupClient ")
public interface CmsUserGroupClient extends ICmsUserGroupController {
}
1.2 bootstrap.yml
server:
port: 32032
servlet:
context-path: /cms-admin
spring:
application:
name: mth-cms-admin
# feign服务名统一配置
feign:
cms:
service:
name: mth-cms-service
1.3 CmsUserGroupController
import com.xxx.cms.admin.service.CmsUserGroupService;
@RestController
public class CmsUserGroupController {
@Autowired
private CmsUserGroupService cmsUserGroupService;
/**
* 分页查询用户组列表,支持模糊搜索
*/
@PostMapping("/user/group/page")
@ApiOperation("分页查询用户组列表 用户组类型:0-静态 1-动态")
MthResponse<PagingResult<CmsUserGroupResp>> getUserGroupPage(@RequestBody(required = false) CmsUserGroupReq cmsUserGroupReq) throws Exception {
return cmsUserGroupService.getUserGroupPage(cmsUserGroupReq);
}
}
1.4 CmsUserGroupService及CmsUserGroupServiceImpl
public interface CmsUserGroupService {
/**
* 分页查询用户组列表
* @param req
* @return PagingResult<CmsUserGroupResp>
* @throws Exception
*/
MthResponse<PagingResult<CmsUserGroupResp>> getUserGroupPage(CmsUserGroupReq req) throws Exception;
}
import com.xxx.cms.admin.service.CmsUserGroupService;
import com.xxx.cms.admin.client.cms.CmsUserGroupClient;
@Slf4j
@Service
public class CmsUserGroupServiceImpl implements CmsUserGroupService {
@Resource
private CmsUserGroupClient cmsUserGroupClient;
/**
* 分页查询用户组列表
*/
@Override
public MthResponse<PagingResult<CmsUserGroupResp>> getUserGroupPage(CmsUserGroupReq req) throws Exception {
MthResponse<PagingResult<CmsUserGroupResp>> resp = cmsUserGroupClient.getUserGroupPage(req);
if(resp.fail()){
ExceptionUtils.create(resp);
}
return resp;
}
}
2 service服务,包括service-api和service-web服务,端口号32031,service-web主启动类要加@EnableFeignClients
2.1service-api服务的ICmsUserGroupController
public interface ICmsUserGroupController {
/**
* 分页查询用户组列表
* @param req
* @return PagingResult<CmsUserGroupResp>
* @throws CommonException
*/
@PostMapping("/user/group/page")
@ApiOperation("分页查询用户组列表")
MthResponse<PagingResult<CmsUserGroupResp>> getUserGroupPage(@RequestBody(required = false) @Param("req") CmsUserGroupReq req) throws CommonException;
}
2.2 service-web服务的bootstrap.yml
server:
port: 32031
spring:
application:
name: mth-cms-service
profiles:
active: local
cloud:
loadbalancer:
ribbon:
enabled: false
fast:
common:
web:
logging:
path: /apps/logs
level: INFO
# feign服务名统一配置
feign:
config:
service:
name: mth-config-service
2.3 service-web服务的CmsUserGroupService及CmsUserGroupServiceImpl
import com.xxx.cms.service.api.entity.CmsUserGroup;
import com.baomidou.mybatisplus.extension.service.IService;
public interface CmsUserGroupService extends IService<CmsUserGroup> {
/**
* 分页查询用户组列表
* @param req
* @return PagingResult<CmsUserGroupResp>
* @throws CommonException
*/
PagingResult<CmsUserGroupResp> getUserGroupPage(CmsUserGroupReq req) throws CommonException;
}
import com.xxx.cms.service.web.service.CmsUserGroupService;
@Service
public class CmsUserGroupServiceImpl extends ServiceImpl<CmsUserGroupMapper, CmsUserGroup>
implements CmsUserGroupService {
/**
* 分页查询用户组列表
* @param req
* @return PagingResult<CmsUserGroupResp>
* @throws CommonException
*/
@Override
public PagingResult<CmsUserGroupResp> getUserGroupPage(CmsUserGroupReq req) {
IPage<CmsUserGroupResp> page = new Page<>(req.getPage(),req.getPageSize());
Page<CmsUserGroupResp> tasks = baseMapper.getUserGroupPage(page,req);
return PagingUtils.getPagingResult(tasks);
}
}