Spring Cloud中间件

一、Nacos+Ribbon

Nacos介绍请参考:什么是 Nacos

下载:https://github.com/alibaba/nacos/releases?page=3

安装方法:Nacos 快速开始

运行nacos:

切换到bin目录,在命令窗口输入命令:sh startup.sh -m standalone

成功启动获取访问地址:http://localhost:8848/nacos/index.html

初始用户名 / 密码:nacos / nacos

微服务注册到Nacos:

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

application.yml:

spring:
  cloud:
    nacos:
      discovery:
        #指定nacos server的地址,用于微服务发现
        server-addr: localhost:8848
        #设置机房名称(指定集群名称)
        cluster-name: BeiJing
        #在nacos中配置命名空间(指定namespace),并且获得uuid
        #namespace: 980af6bb-ce43-43f2-91de-9878ca25fa3e
        #cluster-name: NanJing
        #指定实例元数据
        #metadata:
        #  instance: I'm instance meta data
  application:
#微服务名称
    name: *******
server:
#端口号
  port: ****

同集群优先

package personal.qin.usercenter.configuration;
 
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.util.CollectionUtils;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
 
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
 
    }
 
    @Override
    public Server choose(Object o) {
        try {
            //拿到配置文件中的集群名称BeiJing
            String clusterName = nacosDiscoveryProperties.getClusterName();
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //想要请求的微服务的名称
            String name = loadBalancer.getName();
            //获取服务发现的相关API
            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
 
            //1、找到指定服务的所有实例A
            List<Instance> instances = namingService.selectInstances(name, true);
 
            //2、过滤出相同集群下的所有实例B
            List<Instance> sameClusterInstances = instances.stream().filter(instance -> Objects.equals(instance.getClusterName(), clusterName)).collect(Collectors.toList());
 
            //3、如果B是空,就用A
            List<Instance> instancesToBeChoosen = new ArrayList<Instance>();
            if(CollectionUtils.isEmpty(sameClusterInstances)){
                instancesToBeChoosen = instances;
                log.warn("发生跨集群的调用,name={}, clusterName={}, instances={}", name, clusterName, instances);
            } else {
                instancesToBeChoosen = sameClusterInstances;
            }
 
            //4、基于权重的负载均衡算法,返回一个实例
            Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChoosen);
            log.info("选择的实例是:port={}, instance={}", instance.getPort(), instance);
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("发生异常了", e);
            return null;
        }
    }
}
 
class ExtendBalancer extends Balancer {
    public static Instance getHostByRandomWeight2(List<Instance> hosts){
        return getHostByRandomWeight(hosts);
    }
}

创建Ribbon配置类

注意:该包一定不能和BootApplication同包

package ribbonconfiguration;
 
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import personal.qin.usercenter.configuration.NacosSameClusterWeightedRule;
 
@Configuration
public class RibbonConfiguration {
 
    @Bean
    public IRule ribbonRule(){
        return new NacosSameClusterWeightedRule(); //同集群优先规则
    }
 
}

创建Ribbon全局配置类

package personal.qin.usercenter.configuration;
 
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;
import ribbonconfiguration.RibbonConfiguration;
 
@Configuration
//Ribbon全局配置
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
 
}

二、feign

pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

在BootApplication中添加@EnableFeignClients注解:

package personal.qin.contentcenter;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
@SpringBootApplication
@EnableFeignClients
public class ContentCenterApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ContentCenterApplication.class, args);
    }
 
}

新建FeignClient实现Feign远程请求

package personal.qin.contentcenter.feignclient;
 
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import personal.qin.contentcenter.domain.dto.UserDTO;
 
//Feign访问微服务的名称
@FeignClient(name = "user-center")
public interface UserCenterFeignClient {
    /**
     * Feign会自动构建URL为http://user-center/user/{id}
     * @param id
     * @return
     */
    @GetMapping("/user/{id}")
    UserDTO findById(@PathVariable Integer id);
}

新建测试Controller:

package personal.qin.contentcenter.controller;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import personal.qin.contentcenter.domain.dto.UserDTO;
import personal.qin.contentcenter.feignclient.UserCenterFeignClient;
 
@RestController
@RequestMapping("/content")
public class ContentController {
    @Autowired
    private UserCenterFeignClient userCenterFeignClient;
    @GetMapping("/{id}")
    public UserDTO findById(@PathVariable Integer id){
        return userCenterFeignClient.findById(id);
    }
}

Feign自定义日志级别

在application.yml中结合log添加属性:

#设置日志输出级别
logging:
  level:
    com.itmuch.contentcenter.feignclient.UserCenterFeignClient: debug
feign:
  client:
    config:
      #想要调用的微服务的名称
      user-center:
        loggerLevel: full

 Feign支持的配置项:

多参数可以使用@SpringQueryMap注解实现:

package com.itmuch.contentcenter.feignclient;
 
import com.itmuch.contentcenter.domain.dto.user.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;
 
@FeignClient(name = "user-center")
public interface TestUserCenterFeignClient {
    @GetMapping("/q")
    UserDTO query(@SpringQueryMap UserDTO userDTO);
}

 

在开发中可能会出现多个Feign接口访问同一个微服务的情况,解决方法:

在application.yml中添加属性配置:

spring:
  #解决Feign多个Client接口指向同一个微服务出现异常的问题
  main:
    allow-bean-definition-overriding: true

脱离Nacos单独使用Feign:

package com.itmuch.contentcenter.feignclient;
 
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
 
@FeignClient(name = "baidu", url = "http://www.baidu.com")
public interface TestBaiduFeignClient {
    @GetMapping("")
    public String index();
}
@Autowired
private TestBaiduFeignClient testBaiduFeignClient;
 
@GetMapping("baidu")
public String baiduIndex(){
    return testBaiduFeignClient.index();
}

Feign的性能优化

pom.xml中添加依赖:

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

application.yml中添加属性配置连接池:

feign: 
  httpclient:
    #让feign使用Apache httpclient做请求,而不是默认的urlconnection
    enabled: true
    #feign的最大连接数
    max-connections: 200
    #feign单个路径的最大连接数
    max-connections-per-route: 50

将日志的级别设置为basic,不要使用full

feign:
  client:
    config:
      #想要调用的微服务的名称或全局配置
      default:
        loggerLevel: basic

三、Sentinel

pom.xml中添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml中添加属性配置:

# 配置actuator和Sentinel联动
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

下载Sentinel地址:https://github.com/alibaba/Sentinel/releases

整合微服务到控制台:

在application.yml中配置属性:

spring:
  cloud:
    sentinel:
      transport:
        #指定sentin控制台的地址
        dashboard: localhost:8080

Feign整合Sentinel:

在application.yml中配置属性:

feign:
  sentinel:
    enabled: true

微服务对限流后的处理fallbackfactory

新建工厂类:

package personal.qin.contentcenter.feignclient.fallbackfactory;
 
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import personal.qin.contentcenter.domain.dto.UserDTO;
import personal.qin.contentcenter.feignclient.UserCenterFeignClient;
 
@Slf4j
@Component
public class UserCenterFeignClientFallbackFactory implements FallbackFactory<UserCenterFeignClient> {
    @Override
    public UserCenterFeignClient create(Throwable e) {
        return new UserCenterFeignClient() {
            @Override
            public UserDTO findById(Integer id) {
                log.warn("远程调用被限流或者降级了", e);
                UserDTO userDTO = new UserDTO();
                userDTO.setWxNickname("一个默认用户");
                return userDTO;
            }
        };
    }
}

在Feign的客户端接口上添加引用:

@FeignClient(name = "user-center", fallbackFactory = UserCenterFeignClientFallbackFactory.class)
//name:微服务名称
//fallbackFactory:工厂类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值