软件编程
位置:首页>> 软件编程>> java编程>> springcloud之自定义简易消费服务组件

springcloud之自定义简易消费服务组件

作者:神牛步行3  发布时间:2022-01-29 00:18:24 

标签:springcloud,消费,服务

本次和大家分享的是怎么来消费服务,上篇文章讲了使用Feign来消费,本篇来使用rest+ribbon消费服务,并且通过轮询方式来自定义了个简易消费组件,本文分享的宗旨是:自定义消费服务的思路;思路如果有可取之处还请“赞”一下:

  1. Rest+Ribbon实现消费服务

  2.  Rest+轮询自定义简易消费组件

  3. 使用Scheduled刷新服务提供者信息

Rest+Ribbon实现消费服务

做为服务消费方准确的来说进行了两种主流程区分1)获取可以服务2)调用服务,那么又是如何获取服务的并且又是通过什么来调用服务的,下面我们来看一副手工图:

springcloud之自定义简易消费服务组件

手工图上能够看出消费方先获取了服务方的真实接口地址,然后再通过地址去调用接口;然后对于微服务架构来说获取某一个类ip或端口然后去调用接口肯定是不可取的,因此微服务中产生了一种serviceid的概念;简单流程介绍完了,下面通过实例来分析;首先添加依赖如:


<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

再来我们通过上篇文章搭建的eureka_server(服务中心),eureka_provider(服务提供者)来做测试用例,这里我重新定义eureka_consumer_ribbon模块做为消费服务;先创建service层类和代码:


@Service
public class UserService implements UserInterface {

@Autowired
 protected RestTemplate restTemplate;

@Override
 public MoRp<List<MoUser>> getUsers(MoRq rq) {
   return null;
 }

@Override
 public String getMsg() {

String str = restTemplate.getForObject("http://EUREKA-PROVIDER/msg", String.class);
   return str;
 }
}

主要用到了RestTemplate的 restTemplate.getForObject 函数,然后需要定义个Controller来吧获取到的数据响应到页面上,为了简单这里仅仅只拿getMsg服务接口测试:


@RestController
public class UserController {

@Autowired
 private UserService userService;

@GetMapping("/msg")
 public String getMsg(){

return userService.getMsg();
 }
}

最后我们在启动类添加入下代码,注意 @LoadBalanced 标记必须加,因为咋们引入的eureka依赖里面包含了ribbon(Dalston.RELEASE版本),ribbon封装了负载均衡的算法,如果不加这个注解,那后面rest方法的url就必须是可用的url路径了,当然这里加了注解就可以使用上面说的serviceId:


@SpringBootApplication
@EnableDiscoveryClient //消费客户端
public class EurekaConsumerRibbonApplication {

@Bean
 @LoadBalanced //负载均衡
 RestTemplate restTemplate(){
   return new RestTemplate();
 }

public static void main(String[] args) {
   SpringApplication.run(EurekaConsumerRibbonApplication.class, args);
 }
}

下面来消费方显示的效果:

springcloud之自定义简易消费服务组件

Rest+轮询自定义简易消费组件

自定义消费组件原来和面手工图差不多,就是先想法获取服务提供端真实的接口地址,然后通过rest去调用这个url,得到相应的结果输出;这里自定义了一个ShenniuBanlance的组件类:


/**
* Created by shenniu on 2018/6
* <p>
* rest+eureka+自定义client端
*/
@Component
public class ShenniuBanlance {

@Autowired
 private RestTemplate restTemplate;

@Autowired
 private DiscoveryClient discoveryClient;

/**
  * 服务真实地址 ConcurrentHashMap<"服务应用名称", ("真实接口ip", 被访问次数)>
  */
 public static ConcurrentHashMap<String, List<MoService>> sericesMap = new ConcurrentHashMap<>();

/**
  * 设置服务提供者信息到map
  */
 public void setServicesMap() {
   //获取所有服务提供者applicationName
   List<String> appNames = discoveryClient.getServices();

//存储真实地址到map
   for (String appName :
       appNames) {
     //获取某个服务提供者信息
     List<ServiceInstance> instanceInfos = discoveryClient.getInstances(appName);
     if (instanceInfos.isEmpty()) {
       continue;
     }

List<MoService> services = new ArrayList<>();
     instanceInfos.forEach(b -> {
       MoService service = new MoService();
       //被访问次数
       service.setWatch(0L);
       //真实接口地址
       service.setUrl(b.getUri().toString());
       services.add(service);
     });

//如果存在就更新
     sericesMap.put(appName.toLowerCase(), services);
   }
 }

/**
  * 根据app获取轮询方式选中后的service
  *
  * @param appName
  * @return
  */
 public MoService choiceServiceByAppName(String appName) throws Exception {
   appName = appName.toLowerCase();
   //某种app的服务service集合
   List<MoService> serviceMap = sericesMap.get(appName);
   if (serviceMap == null) {
     //初始化所有app服务
     setServicesMap();
     serviceMap = sericesMap.get(appName);
     if (serviceMap == null) {
       throw new Exception("未能找到" + appName + "相关服务");
     }
   }

//筛选出被访问量最小的service 轮询的方式
   MoService moService = serviceMap.stream().min(
       Comparator.comparing(MoService::getWatch)
   ).get();

//负载记录+1
   moService.setWatch(moService.getWatch() + 1);
   return moService;
 }

/**
  * 自动刷新 服务提供者信息到map
  */
 @Scheduled(fixedDelay = 1000 * 10)
 public void refreshServicesMap() {
   setServicesMap();
 }

/**
  * get请求服务获取返回数据
  *
  * @param appName   应用名称 ApplicationName
  * @param serviceName 服务名称 ServiceName
  * @param map     url上请求参数
  * @param tClass   返回类型
  * @param <T>
  * @return
  */
 public <T> T getServiceData(
     String appName, String serviceName,
     Map<String, ?> map,
     Class<T> tClass) {
   T result = null;
   try {
     //筛选获取真实Service
     MoService service = choiceServiceByAppName(appName);

//请求该service的url
     String apiUrl = service.getUrl() + "/" + serviceName;
     System.out.println(apiUrl);
     result = map != null ?
         restTemplate.getForObject(apiUrl, tClass, map) :
         restTemplate.getForObject(apiUrl, tClass);
   } catch (Exception ex) {
     ex.printStackTrace();
   }
   return result;
 }

/**
  * Service信息
  */
 public class MoService {
   /**
    * 负载次数记录数
    */
   private Long watch;
   /**
    * 真实接口地址: http://xxx.com/api/add
    */
   private String url;

public Long getWatch() {
     return watch;
   }

public void setWatch(Long watch) {
     this.watch = watch;
   }

public String getUrl() {
     return url;
   }

public void setUrl(String url) {
     this.url = url;
   }
 }
}

来源:http://www.cnblogs.com/wangrudong003/p/9134870.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com