个人理解
公司临近过年放假,我所在的项目有这么一个实现,那就是如何维护Oracle数据库不同用户的一张OrgBelong表的数据一致???(这里补充一下,我个人也是第一次使用Oracle数据库,也不是特别熟练Oracle数据库,Oracle就只有一个库,这个库里有不同的用户,不同的用户可以看到不同的表,Oracle数据库中的不同的用户就相当于Mysql中不同的数据库)。但是由于这个项目是针对银行的业务,项目经理说银行那边的技术要求不支持使用Mq,其实这种场景最适合的就是使用消息队列来实现。当时我还建议使用Oracle主从复制,同步数据,这里不现实,因为我们的需求是只要实现这一张OrgBelong表的数据统一。那么我就使用了另外一个思路,就是从注册中心获取所有注册到Eureka的服务,从中过滤掉网关(AGS_SERVER),配置中心(ASCC-SERVER),还有权限控制(AOAS-SERVER),以及当前所在的模块(xxxxx-SERVER)–原因是逻辑在这里实现,不需要重复通过服务调用,我在当前请求的模块中将数据增量的数据打包成报文,剩下的模块中需要都要准备一个接口用于保存增量数据,通过restTemplate来广播发送到其他微服务模块的接口来实现这一业务场景,这种实现方式会很慢,但是我的技术也十分菜鸡,如果各位大佬有更合理的实现方式(其实也就是模拟消息队列的实现)可以评论,我会关注的,谢谢你的浏览,下面我来开始我的代码实现之旅了,首先让我们先来看看如何从注册拉取微服务模块,以及RestTemplate的使用吧。。
拉取注册中心所有服务
启动注册中心Eureka,和两个微服务模块(测试用,那就随意启动两个了,不用在意,重点是下面代码)
使用DiscoveryClient获取
//获取一些配置的信息,得到具体的微服务!
@Autowired
private DiscoveryClient client;
//注册进来的微服务~,获取一些消息~
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> services = client.getServices();
//打印信息:discovery=>services:[springcloud-provider-dept, springcloud-zuul]
System.out.println("discovery=>services:"+services);
//得到一个具体的微服务信息,通过具体的微服务id;
// 通过写在application.yml中配置的spring.application.name=springcloud-provider-dept;
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
测试结果
- 控制台信息
- 浏览器信息
RestTemlate封装请求头HttpHeaders实现调用
这里可以替代RestTemlate的产品有OkHttpClient,WebClient,至于三者的区别,可以百度,这里不做过多解释,下面以RestTemlate为例。
// RestTemplate .... 供我们直接调用就可以了! 注册到Spring中
@Autowired
private RestTemplate restTemplate; //提供多种便捷访问远程http服务的方法,简单的Restful服务模板~
//Ribbon。我们这里的地址,应该是一个变量,通过服务名来访问
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping("/consumer/dept/add")
public String add(Dept dept){
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
headers.add("UserId", "admin");
HttpEntity<String> formEntity = new HttpEntity<String>(JSON.toJSONString(dept), headers);
String s = restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", formEntity, String.class);
return s;
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
我的代码实现
以下代码仅供参考,在实际工作中是不可以直接复制粘贴改参数的,需要你看懂之后然后进行根据思路修改,后期有更好的解决方案我会在博客后面声明的,谢谢你的浏览,代码有什么问题可以评论区留言,毕竟下面这段代码我是凭借记忆高度还原的。
import com.alibaba.fastjson.JSON;
import com.kuang.springcloud.pojo.Dept;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 模拟消息队列刷新服务
*/
public class RefreshServiceUtils {
/**
* 模拟消息队列刷新服务的重载函数
* @param client DiscoveryClient
* @param path 请求后缀路径
* @param dept 请求的增量参数,在公司我使用的是List
*/
public void refreshService(DiscoveryClient client, String path, Dept dept) {
List<String> services = client.getServices();
List<String> exceptServiceList = Arrays.asList("aoas", "ags", "asrc", "ascc", "asma");
List<String> refreshServices = services.stream().filter(serviceId -> !exceptServiceList.contains(serviceId)).collect(Collectors.toList());
for(String serviceId :refreshServices) {
List<ServiceInstance> instances = client.getInstances(serviceId);
//获取请求参数的url路径
String url = "";
for (ServiceInstance instance : instances) {
// instance.getUri()+ 微服务模块路由前缀+path路径(每个公司不一样的)
url = instance.getUri()+serviceId.split("-")[0].toLowerCase()+ path;
}
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
// 请求用户,这里作为mybatis plus的自动填充表的字段数据
headers.add("UserId", "admin");
// 机构信息
headers.add("OrgId", "org");
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> formEntity = new HttpEntity<String>(JSON.toJSONString(dept), headers);
// post请求调参数
String s = restTemplate.postForObject(url, formEntity, String.class);
System.out.println(s);
}
}
}