如何在springcloud中自定义简易消费服务组件

这篇文章给大家介绍如何在springcloud中自定义简易消费服务组件,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:申请域名、网页空间、营销软件、网站建设、耿马网站维护、网站推广。

Rest+Ribbon实现消费服务

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

如何在springcloud中自定义简易消费服务组件

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


  org.springframework.boot
  spring-boot-starter-web


  org.springframework.cloud
  spring-cloud-starter-eureka

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

@Service
public class UserService implements UserInterface {

  @Autowired
  protected RestTemplate restTemplate;

  @Override
  public MoRp> 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
 * 

 * rest+eureka+自定义client端  */ @Component public class ShenniuBanlance {   @Autowired   private RestTemplate restTemplate;   @Autowired   private DiscoveryClient discoveryClient;   /**    * 服务真实地址 ConcurrentHashMap<"服务应用名称", ("真实接口ip", 被访问次数)>    */   public static ConcurrentHashMap> sericesMap = new ConcurrentHashMap<>();   /**    * 设置服务提供者信息到map    */   public void setServicesMap() {     //获取所有服务提供者applicationName     List appNames = discoveryClient.getServices();     //存储真实地址到map     for (String appName :         appNames) {       //获取某个服务提供者信息       List instanceInfos = discoveryClient.getInstances(appName);       if (instanceInfos.isEmpty()) {         continue;       }       List 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 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     * @return    */   public  T getServiceData(       String appName, String serviceName,       Map map,       Class 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;     }   } }

以上就是主要的实现代码,代码逻辑:设置服务提供者信息到map-》根据app获取轮询方式选中后的service-》请求服务获取返回数据;轮询实现的原理是使用了一个负载记录数,每次被请求后自动+1,当要获取某个服务提供者时,通过记录数筛选出最小值的一个实例,里面存储有真实接口地址url;调用只需要这样(当然可以弄成注解来调用):

@Override
  public String getMsg() {

    String str = banlance.getServiceData(
        "EUREKA-PROVIDER", "msg",
        null,
        String.class
    );
    return str;
  }

这里需要注意由于我们在前面RestTemplate使用加入了注解 @LoadBalanced ,这样使得rest请求时必须用非ip的访问方式(也就是必须serviceid)才能正常响应,不然会提示错误如:

如何在springcloud中自定义简易消费服务组件

简单来说就是不用再使用ip了,因为有负载均衡机制;当我们去掉这个注解后,我们自定义的组件就能运行成功,效果图和实例1一样就不贴图了;

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

在微服务架构中,如果某台服务挂了之后,必须要及时更新client端的服务缓存信息,不然就可能请求到down的url去,基于这种考虑我这里采用了EnableSched标记来做定时刷新;首先在启动类增加 @EnableScheduling ,然后定义一个刷行服务信息的服务如:

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

为了方便看测试效果,我们在server,provider(2个),consumer已经启动的情况下,再启动一个端口为2005的provider服务;然后刷新consumer接口看下效果:

如何在springcloud中自定义简易消费服务组件

关于如何在springcloud中自定义简易消费服务组件就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


当前文章:如何在springcloud中自定义简易消费服务组件
分享网址:http://myzitong.com/article/iphsjd.html