springcloud之自定义简易消费服务组件
作者:神牛步行3 发布时间:2022-01-29 00:18:24
本次和大家分享的是怎么来消费服务,上篇文章讲了使用Feign来消费,本篇来使用rest+ribbon消费服务,并且通过轮询方式来自定义了个简易消费组件,本文分享的宗旨是:自定义消费服务的思路;思路如果有可取之处还请“赞”一下:
Rest+Ribbon实现消费服务
Rest+轮询自定义简易消费组件
使用Scheduled刷新服务提供者信息
Rest+Ribbon实现消费服务
做为服务消费方准确的来说进行了两种主流程区分1)获取可以服务2)调用服务,那么又是如何获取服务的并且又是通过什么来调用服务的,下面我们来看一副手工图:
手工图上能够看出消费方先获取了服务方的真实接口地址,然后再通过地址去调用接口;然后对于微服务架构来说获取某一个类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);
}
}
下面来消费方显示的效果:
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


猜你喜欢
- 一、C语言关键字详解1. sizeof sizeof相信大
- 常见尺寸单位Android开发中的常用尺寸单位有如下几种:dp (dip)pxptinchsp算不知道确切含义,相信对于以上这几种尺寸单位大
- flex 布局算法Flutter 弹性布局的基石 是 flex 和 flexible。理解了这两个 widget,后面的row,column
- 首先客户端从服务器端获取json数据1、利用HttpUrlConnection/** &nbs
- 本文实例讲述了Spring与Struts整合之让Spring管理控制器操作。分享给大家供大家参考,具体如下:一 Web配置<?xml
- 背景现行的文本编辑器大多都具备文本查询的能力,但是并不能直观的告诉用户两段文字的细微差异,所以对比工具在某种情况下,就起到了很便捷的效率。关
- 1.项目简绍本项目使用SpringBoot开发,jdbc5.1.48 Mybatis 源码可下载其中涉及功能有:Mybatis的使用,Thy
- 方案一: 采用reflections 框架(此框架依赖com.google.guava)1、reflections框架地址:https://
- 本文实例讲述了Android开发中4个常用的工具类。分享给大家供大家参考,具体如下:1、土司工具类(Toast管理)/** * Toast统
- 将字母全部转换为大写或小写,在C#编程中是一个非常常见的功能。在开发过程中,经常需要验证用户登录,用户在输入用户名时可能不区分大小写,如果我
- 1.选择排序(冒泡排序)升序用第一个元素跟其他元素比较,如果该元素比其他元素,则交换,保证该元素是最小的。然后再用第二个元素跟后面其他的比较
- 改进思考正常实现流程应该为继承ClassLoader虚拟类,并重写其loadClass方法和findClass方法,并在loadClass方
- android的WebView组件可以说是相当的强大,现将项目中经常用到的几个功能总结如下:一、背景设置WebView.setBackgro
- 1.什么是servlet?sun(oracle)公司制订的一种用来扩展web服务器端功能的组件规范。背景:常用的web服务器:apache
- 1、什么是序列化与反序列化?序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传
- 我对java中lambda表达式的看法是相当纠结的:一个我这么想:lambda表达式降低了java程序的阅读体验。java程序一直不以表现力
- C# Linq延迟查询在定义linq查询表达式时,查询是不会执行,查询会在迭代数据项时运行。它使用yield return 语句返回谓词为t
- 在很多系统开发中,我们希望在指定的方法调用之前或者之后能打印出该方法的调用时间以及方法的出参和入参,就可以使用spring的AOP,还可以结
- 更正说明:我之前的的标题有点文不对题,我这篇博客的内容明明说的是:java中对象创建的过程,对内存之种底层的东西,我其实提的不太多。所以我原
- 其实就只有一条sql语句<select id = "search" resultType = "mate