使用OpenFeign进行服务间的调用
一、注册服务(nacos)
- pom.xml中添加配置
<!--========================nacos 配置============================-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--========================nacos 配置结束========================-->
- application.properties
# 访问路径
server.servlet.context-path=/
spring.profiles.active=dev
### Nacos配置中心
spring.cloud.nacos.config.prefix=xxx
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.group=DEFAULT_GROUP
spring.cloud.nacos.config.server-addr=xxxxxx:8848
### Nacos注册中心
spring.cloud.nacos.discovery.group=DEFAULT_GROUP
spring.cloud.nacos.discovery.server-addr=xxxxx:8848
- 在启动类添加注解@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("xxx")
public class XxxxApplication {
private static final Logger logger =
public static void main(String[] args) {
ConfigurableApplicationContext application = SpringApplication.run(XxxxApplication.class, args);
}
}
- 随后,启动工程,并在nacos上查看是否服务注册成功。
二、服务间调用
使用open feign
pom.xml
<!--========================open feign 配置========================-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--========================open feign 配置结束========================-->
application.properties
### feign请求
ribbon.ConnectTimeout=5000
ribbon.ReadTimeout=120000
服务提供方:
/**
* 测试feign 服务提供着
*
* @author wangwei
*/
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(User user) {
System.out.println("啊!我被 " + user.getUserName() + " 调用了");
return "hello world!";
}
}
服务调用方:
- 在启动类添加注解@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("xxx")
public class XxxxApplication {
private static final Logger logger =
public static void main(String[] args) {
ConfigurableApplicationContext application = SpringApplication.run(XxxxApplication.class, args);
}
}
- client
@FeignClient(value = "provide-server-name")
public interface HelloClient {
@GetMapping("/hello")
String hello();
}
provide-server-name: nacos上服务提供方的服务名
/hello对应服务提供方接口uri
注意:配置文件中的server.servlet.context-path=/,使得此时调用路径为:xxxx/provide-server-name/hello
- controller调用此client
@RestController
public class HelloController {
@Autowired
HelloClient helloClient;
@RequestMapping("/helloFeign")
public String feignTest(HttpServletRequest request, User user) {
System.out.println(request);
System.out.println(user.toString());
return helloClient.hello();
}
}
三、open feign进行服务间调用时带上请求头信息
添加FeignRequestHeaderInterceptor.java中断所有feign请求
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
* Feign请求拦截器(设置请求头,传递登录信息)
*
* @author wangwei
**/
@Configuration
public class FeignRequestHeaderInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
requestTemplate.header(name, values);
}
}
}
}
在配置文件中添加(策略)
hystrix.command.default.execution.isolation.strategy=SEMAPHORE
四、open feign进行服务间调用时传输MultipartFile file
在client中指定content-type(form-data)
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
/**
* 文件上传接口
*
* @author wangwei
*/
@FeignClient(value = "emptech-file")
public interface FileClient {
/**
* 通用文件上传接口
*
* @param file formData file
* @return java.lang.String
* @author wangwei
* @date 2020-11-13 9:25
*/
@PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
R<CommonFile> uploadFile(MultipartFile file);
}
然后在之前配置的FeignRequestHeaderInterceptor中过滤掉content-length(解决feign.RetryableException: Incomplete output stream executing)
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
* Feign请求拦截器(设置请求头,传递登录信息)
*
* @author wangwei
**/
@Configuration
public class FeignRequestHeaderInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
//解决文件无法上传问题
if ("content-length".equals(name)) {
continue;
}
requestTemplate.header(name, values);
}
}
}
}