Feign 微服务调用 (nacos 作为注册中心)

Feign 微服务调用 (nacos 作为注册中心)

Feign 是 spring Cloud Netflix 组件中的一量级 Restful的HTTP 服务客户端,实现了负载均衡和 Rest 调用的开源框架,封装了RibbonRestTemplate,实现WebService的面向接口编程。

Feign 简化了RestTemplate代码,是声明式服务调用组件:核心就是像调用本地方法一样调用远程方法。让开发者无需关注,远程调用过程,和交互细节。

Feign 本身并不支持spring MVC注解,它有一套自己的注解,为了更方便使用Spring Cloud孵化OpenFeign。并且支持spring mvc的注解,例如:@RequestMapping、@PathVariable。

openFeign 的@FeignClient可以解析Spring MVC@RequestMapping注解下的接口,并通过动态代理方式产生实现类,实现类中做负载均衡调用服务。

soringboot 2.0 以后基本使用 OpenFeign

官网

特性

  • Hystrix 和它的 Fallback
  • HTTP 请求响应的压缩
  • Ribbon 负载均衡客户端
  • 可拔插的HTTP编码器和解码器
  • 拔插的注解支持,包括Feign 注解 和JAX-RS 注解

快速开始

项目预览

image-20220507201640659

项目

pom 文件

父项目

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <!-- 利用传递依赖,公共部分 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
    </dependencies>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--注意:这里需要添加以下配置,否则可能会有各种依赖问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

goods 消费者

    <parent>
        <artifactId>springcloud-openfeig</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeig-goods</artifactId>
    <description>商品服务</description>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

order 生产者

    <parent>
        <artifactId>springcloud-openfeig</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeig-order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
<!--        openfeign 依赖的 服务调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

goods

server:
  port: 8081
spring:
  application:
    name: openfeig-goods
  cloud:
    nacos:
      server-addr: ...:8848
@RestController
public class GoodsController {

    @GetMapping("hello/{message}")
    public String hello(@PathVariable String message){
        return "来自goods的消息 =="+ message;
    }
}

order

server:
  port: 8080
spring:
  application:
    name: openfeig-order
  cloud:
    nacos:
      server-addr: ....:8848
@SpringBootApplication
//开启远程调用的注解 扫描,可以扫描 @FeignClient
@EnableFeignClients
public class OpenFeigOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OpenFeigOrderApplication.class,args);
    }
}
// 准备远程调用的接口
@FeignClient(name = "openfeig-goods")
public interface  GoodsClienService {

    @GetMapping("hello/{message}")
    String hello(@PathVariable String message);
}
//提供对外暴露的 api
@RestController
public class OrderController  {

    //nacos 客户端信息
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    //调用的 service
    @Autowired
    private GoodsClienService cartService;

    @GetMapping("add/{message}")
    public String add(@PathVariable String message){
        ServiceInstance choose = loadBalancerClient.choose("openfeig-goods");
        return cartService.hello(message) +"  "+ choose.getHost() + "--" + choose.getPort();
    }
}

测试

image-20220507202450084

@FeignClient ‼️

需要 @EnableFeignClients来开启扫描

当定义的Feign接口中的方法被调用时,通过JDK的代理方式,生成具体的 RequestTemplate。这个对象中,封装了http需要的全部信息。参数、方法名等等

属性说明
name指定FeignClient等名称,如果项目使用了Ribbon,那么name属性会作为微服务等名称,用于服务发现
url一般用于调试,可以手动指定@FeignClient调用的服务地址
decode404当发生404错误时,如果该字段值为true,会调用decoder进行编码,否则抛出FeignException
configurationFeign 配置列,可以自定义Feign 的 Encoder、Decoder、LogLevel、Contract
也可以在配置文件中配置
fallback定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现 @FeignClient标记的接口
fallbackFactory工厂类,用于生成fallback类实例,通过这个属性可以实现每个接口通用的容错逻辑,减少重复的代码
path定义当前FeignClient 的统一前缀

Feign 日志开启

需要在配置文件中 logback.xml 把日志级别改为debug

# open feign 日志设置
logging:
  level:
    com.springcloud.study.service.ProviderClientService: debug
//全局的配置 日志配置类
@Configuration
public class FeignServiceConfig {

    /*
    Logger.Level 设置级别
    NONE : 不记录任何信息
    BASIC: 仅记录请求方法,URL以及响应状态码
    HEADERS: 除了记录 BASIC级别信息外,还会记录请求和响应的头信息
    FULL: 记录所有的请求于响应的明细,包括头信息,请求体,元数据
     */
    @Bean
    Logger.Level feignLogger(){
        return Logger.Level.FULL;
    }
}
//指定单独的配置 MyFeignConfig 是一个 日志的配置类
@FeignClient(configurtion = MyFeignConfig.class)

HTTP Client 替换

Feign 默认使用的是JDK原生的 URLConnection发送HTTP请求,没有用链接池。对每个地址都会建立一个长链接。

feign 的HTTP客户端支持3中框架HttpURLConnection、HttpClient、OkHttp

默认是 HttpURLConnection

修改

<!-- feign httpclient -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

<!-- 或者换成okhttp -->
<!-- 引入 Feign 对 Okhttp 的支持 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
feign:
  httpclient:
    # 开启httpclient
    enabled: true

如果使用 okhttp 的可以自定义配置

okHttp 优势

  1. 支持SPDY,合并多个请求到同一个主机
  2. 使用链接池
  3. 使用GZIP压缩减少传输数据体积
  4. 缓存响应结果,减少重复请求
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {

    @Bean
    public okhttp3.OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS) //链接超时时间
                .readTimeout(60,TimeUnit.SECONDS)     //读超时
                .writeTimeout(60,TimeUnit.SECONDS)     //写超时
                .retryOnConnectionFailure(true)                 //自动重试
                .connectionPool(new ConnectionPool())           //创建链接池 okhttp包的
                .build();
    }
}

参数传递

get 方式,@PathVariable、@RequestParm注解来接收

post 方式 ,@RequestBody接收请求参数

特殊需求,Get方法传递了多参数

需要时实现Feign 的RequestInterceptor中的pally进行统一处理

TODO 还是用 post 方法发送省事

实现Token 传递

认证鉴权的时候,使用JWT,或spring security 都需要拿到token

RequestInterceptor 拦截器,在feign 调用的时候,向请求头里添加需要传递的token

基于上面的代码改动 注意token 大小写的问题

//生产端
@Component
public class FeignTokenAddInterceptor  implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        if(null==getHttpServletRequest()){
            //此处省略日志记录
            return;
        }
        //将获取Token对应的值往下面传
        requestTemplate.header("oauthToken", getHeaders(getHttpServletRequest()).get("oauthtoken"));
    }

    private HttpServletRequest getHttpServletRequest() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Feign拦截器拦截请求获取Token对应的值
     * @param request
     * @return
     */
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }

        System.out.println("模拟token " +  map.get("oauthtoken"));

        return map;
    }
}

    @GetMapping("hello/{message}")
    public String hello(@PathVariable("message") String message, HttpServletRequest req){

        String oauthToken = req.getHeader("oauthToken");
        System.out.println( "token =" + oauthToken);

        return "来自goods的消息 =="+ message + oauthToken;
    }

image-20220508153045445

底部

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下步骤实现FeignNacos的https微服务调用: 1. 在Nacos中配置https协议的微服务实例,确保服务已经正常运行。 2. 在Feign客户端中配置https请求的方式,可以参考以下代码: ```java @Configuration public class FeignHttpsConfig { @Bean public OkHttpClient okHttpClient() { return new OkHttpClient.Builder() .sslSocketFactory(createSSLSocketFactory()) .hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }) .build(); } private SSLSocketFactory createSSLSocketFactory() { SSLSocketFactory sslSocketFactory = null; try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, new SecureRandom()); sslSocketFactory = sslContext.getSocketFactory(); } catch (Exception e) { e.printStackTrace(); } return sslSocketFactory; } } ``` 3. 在Feign客户端中使用@FeignClient注解指定微服务名称,并通过@RequestLine注解指定https请求的方式,例如: ```java @FeignClient(name = "example-service", configuration = FeignHttpsConfig.class) public interface ExampleFeignClient { @RequestLine("GET /example") String getExample(); } ``` 4. 在应用启动类中添加@EnableFeignClients注解,以启用Feign客户端。 5. 调用Feign客户端的方法即可实现https微服务调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值