当前位置: 首页 > news >正文

深圳保障房seo线下培训班

深圳保障房,seo线下培训班,网站建设扌金手指六六,产品备案查询文章目录 Nacos定义服务注册与订阅方法服务信息加载与配置实现将网关注册到注册中心实现服务的订阅 Nacos Nacos提供了许多强大的功能: 比如服务发现、健康检测。 Nacos支持基于DNS和基于RPC的服务发现。 同时Nacos提供对服务的实时的健康检查,阻止向不…

文章目录

  • Nacos
  • 定义服务注册与订阅方法
  • 服务信息加载与配置
  • 实现将网关注册到注册中心
  • 实现服务的订阅

Nacos

Nacos提供了许多强大的功能:
比如服务发现、健康检测。
Nacos支持基于DNS和基于RPC的服务发现。
同时Nacos提供对服务的实时的健康检查,阻止向不健康的主机活服务发送请求。
并且Nacos也提供了一个可视化的控制台方便我们对实例等信息进行管理。
同时Nacos提供了动态配置服务,可以让我们以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置

在这里插入图片描述

Nacos是我在开发自己项目过程中用的最多的一个注册中心和配置中心,并且Nacos的社区相对其他的来说更加活跃,代码也更加容易阅读。
如下是Nacos官网:Nacos官网
我就不再这篇文章里面过多的讲解Nacos的一些特性了。
在这一章节中,我将使用Nacos暴露出来的接口,来完成项目的服务注册功能以及服务发现功能。
完成这一章的学习也会让你更加深入的了解到Nacos的底层运行原理,注册中心原理。
下面是一些我曾经学习Nacos过程中编写的一些文章,有兴趣可以看看。
使用Nacos实现动态线程池技术以及Nacos配置文件更新监听事件
【源码分析】Nacos如何使用AP协议完成服务端之间的数据同步?
【源码分析】Nacos服务端如何更新以及保存注册表信息?
Nacos自动注册原理实现以及服务注册更新并如何保存到注册表

为什么选择Nacos之前的文章简单讲解过,这里我将详细的列举出几个原因:

  • Nacos 提供了让我从微服务平台建设的视角管理数据中心的所有服务及元数据,具体原因可以看看上面我对Nacos源码的分析,Nacos将服务细粒度的划分为了各自实例,并且我们可以管理这些实例的信息
  • Nacos支持基于DNS和基于RPC的服务发现,这也就意味着提供给我们较强的服务发现的选择能力
  • Nacos提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求,也就是安全
  • 动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置,我之前也已经利用过这一点来实现对线程池的动态配置具体可以查看这篇文章

定义服务注册与订阅方法

在这一步,我们将需要定义一些网关项目用于连接到Nacos这个注册中心的接口,来实现会将我们的项目链接到注册中心。
要将一个服务注册到注册中心,大概需要初始化、注册、取消注册、服务订阅等方法,也就是我们需要编写一个如下的接口来提供这样子的一个接口并在后面的具体注册中心实例中去实现这个接口方法。

public interface RegisterCenter {/***   初始化* @param registerAddress  注册中心地址* @param env  要注册到的环境*/void init(String registerAddress, String env);/*** 注册* @param serviceDefinition 服务定义信息* @param serviceInstance 服务实例信息*/void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance);/*** 注销* @param serviceDefinition* @param serviceInstance*/void deregister(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance);/*** 订阅所有服务变更* @param registerCenterListener*/void subscribeAllServices(RegisterCenterListener registerCenterListener);
}

实现完毕接口之后,我们还需要提供一个方法,它的作用是用于监听注册中心的配置的变更。
这也是Nacos作为注册中心和配置中心特别重要的一个功能,接口定义如下:

public interface RegisterCenterListener {void onChange(ServiceDefinition serviceDefinition,Set<ServiceInstance> serviceInstanceSet);
}

服务信息加载与配置

基于上面的服务注册与订阅接口,我们就可以大致编写出来如何将我们的网关注册到Nacos中了。当然,我们还没有具体实现如何注册到Nacos注册中心的方法,但是我们可以先编写出来其大致的一个调用方法。


@Slf4j
public class Bootstrap
{public static void main( String[] args ){//加载网关核心静态配置Config config = ConfigLoader.getInstance().load(args);System.out.println(config.getPort());//插件初始化//配置中心管理器初始化,连接配置中心,监听配置的新增、修改、删除//启动容器Container container = new Container(config);container.start();//连接注册中心,将注册中心的实例加载到本地final RegisterCenter registerCenter = registerAndSubscribe(config);//服务优雅关机//进程收到kill信号的时候进行一个注销操作Runtime.getRuntime().addShutdownHook(new Thread(){/*** 下线操作*/@Overridepublic void run(){registerCenter.deregister(buildGatewayServiceDefinition(config),buildGatewayServiceInstance(config));}});}/*** 当前方法用于提供注册和订阅服务信息变更通知* @param config* @return*/private static RegisterCenter registerAndSubscribe(Config config) {//加载服务提供者  具体这里的作用可以 查看我的博客ServiceLoader<RegisterCenter> serviceLoader = ServiceLoader.load(RegisterCenter.class);final RegisterCenter registerCenter = serviceLoader.findFirst().orElseThrow(() -> {log.error("not found RegisterCenter impl");return new RuntimeException("not found RegisterCenter impl");});//初始化注册中心信息registerCenter.init(config.getRegistryAddress(), config.getEnv());//构造网关服务定义和服务实例ServiceDefinition serviceDefinition = buildGatewayServiceDefinition(config);ServiceInstance serviceInstance = buildGatewayServiceInstance(config);//注册registerCenter.register(serviceDefinition, serviceInstance);//订阅registerCenter.subscribeAllServices(new RegisterCenterListener() {@Overridepublic void onChange(ServiceDefinition serviceDefinition, Set<ServiceInstance> serviceInstanceSet) {log.info("refresh service and instance: {} {}", serviceDefinition.getId(),JSON.toJSON(serviceInstanceSet));DynamicConfigManager manager = DynamicConfigManager.getInstance();manager.addServiceInstance(serviceDefinition.getId(), serviceInstanceSet);}});return registerCenter;}/*** 构建网关服务实例* @param config* @return*/private static ServiceInstance buildGatewayServiceInstance(Config config) {String localIp = NetUtils.getLocalIp();int port = config.getPort();ServiceInstance serviceInstance = new ServiceInstance();serviceInstance.setServiceInstanceId(localIp + COLON_SEPARATOR + port);serviceInstance.setIp(localIp);serviceInstance.setPort(port);serviceInstance.setRegisterTime(TimeUtil.currentTimeMillis());return serviceInstance;}/*** 构建网关服务定义信息* @param config* @return*/private static ServiceDefinition buildGatewayServiceDefinition(Config config) {ServiceDefinition serviceDefinition = new ServiceDefinition();serviceDefinition.setInvokerMap(Map.of());serviceDefinition.setId(config.getApplicationName());serviceDefinition.setServiceId(config.getApplicationName());serviceDefinition.setEnvType(config.getEnv());return serviceDefinition;}}

其中比较重要的就是这一行代码,也就是加载服务提供者

ServiceLoader.load(RegisterCenter.class) 

ServiceLoader是 Java 中用于加载服务提供者的工具,通常用于实现服务提供者框架。它的作用是查找和加载指定接口或抽象类的服务提供者实现类,这些实现类在运行时动态注册到系统中,以便其他组件或应用程序可以使用它们的功能。

具体来说,以下是它的作用和用法:

  • 服务接口定义:首先,您需要定义一个服务接口或抽象类,这是您想要不同实现的抽象描述。在您的例子中,RegisterCenter.class 似乎是一个服务接口。

  • 服务提供者实现:不同的模块或库可以提供服务接口的不同实现,这些实现类可以独立于应用程序开发并且可以在运行时加载。

  • 服务提供者注册:每个服务提供者实现类需要在 META-INF/services 目录下创建一个文件,该文件的名称是服务接口的全限定名,内容是服务提供者实现类的全限定名。这告诉 Java 运行时系统哪些类实现了该服务接口。

  • 加载服务提供者:使用 ServiceLoader.load(RegisterCenter.class),您可以加载所有已经注册的服务提供者实现类。这返回一个 ServiceLoader 对象,您可以迭代这个对象以获取所有已加载的实现类的实例。

这个机制允许应用程序在不修改源代码的情况下动态地切换和使用不同的服务提供者实现,从而提高了应用程序的可扩展性和灵活性。它通常用于框架和库,以允许开发者插入他们自己的实现,例如数据库驱动程序、日志记录器、插件等。

实现将网关注册到注册中心

想要将网关注册到注册中心,我们首先需要引入Nacos的客户端依赖。

       <!--引入Nacos的客户端依赖--><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>2.0.4</version></dependency><!--导入我们直接实现的注册中心接口--><dependency><groupId>blossom.project</groupId><artifactId>BlossomGateway-Register-Center-Api</artifactId><version>1.0</version></dependency></dependencies>

之后,我们就可以使用Nacos客户端中提供的服务注册方法进行服务注册了。
方式如下:


@Slf4j
public class NacosRegisterCenter implements RegisterCenter {/*** 注册中心的地址*/private String registerAddress;/*** 环境选择*/private String env;/*** 主要用于维护服务实例信息*/private NamingService namingService;/*** 主要用于维护服务定义信息*/private NamingMaintainService namingMaintainService;/*** 监听器列表* 这里由于监听器可能变更 会出现线程安全问题*/private List<RegisterCenterListener> registerCenterListenerList = new CopyOnWriteArrayList<>();@Overridepublic void init(String registerAddress, String env) {this.registerAddress = registerAddress;this.env = env;try {this.namingMaintainService = NamingMaintainFactory.createMaintainService(registerAddress);this.namingService = NamingFactory.createNamingService(registerAddress);} catch (NacosException e) {throw new RuntimeException(e);}}@Overridepublic void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {try {//构造nacos实例信息Instance nacosInstance = new Instance();nacosInstance.setInstanceId(serviceInstance.getServiceInstanceId());nacosInstance.setPort(serviceInstance.getPort());nacosInstance.setIp(serviceInstance.getIp());//实例信息可以放入到metadata中nacosInstance.setMetadata(Map.of(GatewayConst.META_DATA_KEY, JSON.toJSONString(serviceInstance)));//注册namingService.registerInstance(serviceDefinition.getServiceId(), env, nacosInstance);//更新服务定义namingMaintainService.updateService(serviceDefinition.getServiceId(), env, 0,Map.of(GatewayConst.META_DATA_KEY, JSON.toJSONString(serviceDefinition)));log.info("register {} {}", serviceDefinition, serviceInstance);} catch (NacosException e) {throw new RuntimeException(e);}}
}

这里需要对Nacos的源码有了解,你才能明白如何将一个服务实例注册到Nacos的注册中心,Nacos这边要求你提供服务的ip、端口、服务名称等信息。
完成这一步之后,我们大概就已经成功的将服务注册到Nacos了。

实现服务的订阅

这里我们开始实现服务订阅,要想实现服务订阅,首先需要拉取Nacos上面的所有的服务的信息,并且服务信息会不断的更新变化,因此我们还需要使用定时任务的方式不断的更新我们的服务订阅信息。
要先实现对Nacos服务信息的订阅,需要用到Nacos的事件监听器,NamingEvent。
在Nacos注册中心中,NamingEvent 是一个事件对象,用于表示与服务命名空间(Naming)相关的事件。NamingEvent 的作用是用于监听和处理命名空间中的服务实例(Service Instance)的变化,以便应用程序可以根据这些变化来动态地更新服务实例列表,以保持与注册中心的同步。

具体来说,NamingEvent 主要用于以下目的:

  • 监听服务实例的变化:Nacos注册中心可以包含大量的服务实例,而这些实例可能会因服务上线、下线、实例元数据变化等原因而发生变化。NamingEvent 允许应用程序注册监听器,以便在服务实例发生变化时得到通知。

  • 动态更新服务实例列表:通过监听 NamingEvent,应用程序可以实时获得有关服务实例的状态变化,从而可以及时更新自己维护的服务实例列表,以确保使用最新的服务实例信息。

  • 实现负载均衡:应用程序可以根据 NamingEvent 提供的信息来实现负载均衡策略,例如选择合适的服务实例以提供服务请求。负载均衡策略可以根据服务实例的可用性、健康状态和其他元数据来进行调整。

  • 动态路由:一些应用程序可能需要实现动态路由,根据服务实例的变化来动态更新路由规则,以确保请求被正确路由到可用的服务实例。

大致的代码实现如下:

 @Overridepublic void subscribeAllServices(RegisterCenterListener registerCenterListener) {//服务订阅首先需要将我们的监听器加入到我们的服务列表中registerCenterListenerList.add(registerCenterListener);//进行服务订阅doSubscribeAllServices();//可能有新服务加入,所以需要有一个定时任务来检查ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1, new NameThreadFactory("doSubscribeAllServices"));//循环执行服务发现与订阅操作scheduledThreadPool.scheduleWithFixedDelay(() -> doSubscribeAllServices(), 10, 10, TimeUnit.SECONDS);}private void doSubscribeAllServices() {try {//得到当前服务已经订阅的服务//这里其实已经在init的时候初始化过namingservice了,所以这里可以直接拿到当前服务已经订阅的服务//如果不了解的可以debugSet<String> subscribeService =namingService.getSubscribeServices().stream().map(ServiceInfo::getName).collect(Collectors.toSet());int pageNo = 1;int pageSize = 100;//分页从nacos拿到所有的服务列表List<String> serviseList = namingService.getServicesOfServer(pageNo, pageSize, env).getData();//拿到所有的服务名称后进行遍历while (CollectionUtils.isNotEmpty(serviseList)) {log.info("service list size {}", serviseList.size());for (String service : serviseList) {//判断是否已经订阅了当前服务if (subscribeService.contains(service)) {continue;}//nacos事件监听器 订阅当前服务//这里我们需要自己实现一个nacos的事件订阅类 来具体执行订阅执行时的操作EventListener eventListener = new NacosRegisterListener();eventListener.onEvent(new NamingEvent(service, null));namingService.subscribe(service, env, eventListener);log.info("subscribe {} {}", service, env);}//遍历下一页的服务列表serviseList = namingService.getServicesOfServer(++pageNo, pageSize, env).getData();}} catch (NacosException e) {throw new RuntimeException(e);}}/*** 实现对nacos事件的监听器* NamingEvent 是一个事件对象,用于表示与服务命名空间(Naming)相关的事件。* NamingEvent 的作用是用于监听和处理命名空间中的服务实例(Service Instance)的变化,* 以便应用程序可以根据这些变化来动态地更新服务实例列表,以保持与注册中心的同步。*/public class NacosRegisterListener implements EventListener {@Overridepublic void onEvent(Event event) {if (event instanceof NamingEvent) {log.info("the triggered event info is:{}",JSON.toJSON(event));NamingEvent namingEvent = (NamingEvent) event;String serviceName = namingEvent.getServiceName();try {//获取服务定义信息Service service = namingMaintainService.queryService(serviceName, env);ServiceDefinition serviceDefinition =JSON.parseObject(service.getMetadata().get(GatewayConst.META_DATA_KEY),ServiceDefinition.class);//获取服务实例信息List<Instance> allInstances = namingService.getAllInstances(service.getName(), env);Set<ServiceInstance> set = new HashSet<>();for (Instance instance : allInstances) {ServiceInstance serviceInstance =JSON.parseObject(instance.getMetadata().get(GatewayConst.META_DATA_KEY),ServiceInstance.class);set.add(serviceInstance);}registerCenterListenerList.stream().forEach(l -> l.onChange(serviceDefinition, set));} catch (NacosException e) {throw new RuntimeException(e);}}}}

此时,我们就完成了在Nacos注册中心发生信息变更的时候,能在一次拉取到最新的配置信息。也就是我们完成了对注册中心的订阅。

http://www.dinnco.com/news/28367.html

相关文章:

  • 广州市网站建设公司优化精灵
  • 济南营销型网站制作关于seo的行业岗位有哪些
  • 怎么做博彩网站如何自己创造一个网站平台
  • 北京网站建设公司案例深圳媒体网络推广有哪些
  • 用h5做简易网站代码18种最有效推广的方式
  • 比较好的做外贸网站信息检索关键词提取方法
  • 太原做网站的公司排行千锋教育怎么样
  • 网站如何做微信支付手机百度云网页版登录
  • 一级做爰片软件网站如何优化关键词
  • 财佰通突然做网站维护站长之家seo综合查询
  • 设计一个自己的电商网站宁波seo在线优化哪家好
  • 石家庄市网站制作黑龙江新闻
  • 辽宁营商环境建设局网站pr的选择应该优先选择的链接为
  • 制作一个网站需要什么九江seo
  • 八宝山做网站的公司市场调研报告
  • 网站建设加盟新闻软文怎么写
  • 响应式网站概况搜索引擎推广方法
  • 专做定制网站建设网络运营培训课程
  • 学校做网站及费用网络推广外包公司干什么的
  • 做ppt设计师哪个网站好专业seo公司
  • 邳州哪家做百度推广网站seo百度关键词优化软件
  • 北京网站提升排名品牌策略怎么写
  • 宁波公司网站建设定制服务常见网络营销推广方法
  • 怎么做动漫网站网上做广告怎么收费
  • 做网页用的网站信息流优化师工作内容
  • 可以做动漫的网站有哪些如何自己做一个网址
  • 大网站制作公司公司网站模板
  • 如何做网站程序新乡百度关键词优化外包
  • 开发网站用什么语言最好吗电脑上突然出现windows优化大师
  • 外国语学院英文网站建设seo哪个软件好