范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

重写Nacos服务发现多个服务器如何跨命名空间,访问公共服务?

  一、问题背景
  在开发某个公共应用时,笔者发现该公共应用的数据是所有测试环境(假设存在 dev/dev2/dev3)通用的。
  这就意味着只需部署一个应用,就能满足所有测试环境的需求;也意味着所有测试环境都需要调用该公共应用,而不同测试环境的应用注册在不同的 Nacos 命名空间。
  二、两种解决方案
  如果所有测试环境都需要调用该公共应用,有两种可行的方案。第一种,将该公共服务同时注册到不同的测试环境所对应的命名空间中。
  第二种,将公共应用注册到单独的命名空间,不同的测试环境能够跨命名空间访问该应用。
  三、详细的问题解决过程
  先行交代笔者的版本号配置。Nacos 客户端版本号为  NACOS 1.4.1 ;Java 项目的 Nacos 版本号如下。
  最初想法是将该公共应用同时注册到多个命名空间下。在查找资料的过程中,团队成员在  GitHub  上发现了一篇类似问题的博客分享:Registration Center: Can services in different namespaces be called from each other? #1176。
  01 注册多个命名空间
  从该博客中,我们看到其他程序员朋友也遇到了类似的公共服务的需求。在本篇文章中,笔者将进一步分享实现思路以及示例代码。
  说明:以下代码内容来自用户 chuntaojun 的分享。  shareNamespace={namespaceId[:group]},{namespaceId[:group]}  @RunWith(SpringRunner.class) @SpringBootTest(classes = NamingApp.class, properties = {"server.servlet.context-path=/nacos"},     webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class SelectServiceInShareNamespace_ITCase {      private NamingService naming1;     private NamingService naming2;     @LocalServerPort     private int port;     @Before     public void init() throws Exception{         NamingBase.prepareServer(port);         if (naming1 == null) {             Properties properties = new Properties();             properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1"+":"+port);             properties.setProperty(PropertyKeyConst.SHARE_NAMESPACE, "57425802-3058-4507-9a73-3229b9f00a36");             naming1 = NamingFactory.createNamingService(properties);              Properties properties2 = new Properties();             properties2.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1"+":"+port);             properties2.setProperty(PropertyKeyConst.NAMESPACE, "57425802-3058-4507-9a73-3229b9f00a36");             naming2 = NamingFactory.createNamingService(properties2);         }         while (true) {             if (!"UP".equals(naming1.getServerStatus())) {                 Thread.sleep(1000L);                 continue;             }             break;         }     }      @Test     public void testSelectInstanceInShareNamespaceNoGroup() throws NacosException, InterruptedException {         String service1 = randomDomainName();         String service2 = randomDomainName();         naming1.registerInstance(service1, "127.0.0.1", 90);         naming2.registerInstance(service2, "127.0.0.2", 90);          Thread.sleep(1000);          List instances = naming1.getAllInstances(service2);         Assert.assertEquals(1, instances.size());         Assert.assertEquals(service2, NamingUtils.getServiceName(instances.get(0).getServiceName()));     }      @Test     public void testSelectInstanceInShareNamespaceWithGroup() throws NacosException, InterruptedException {         String service1 = randomDomainName();         String service2 = randomDomainName();         naming2.registerInstance(service1, groupName, "127.0.0.1", 90);         naming3.registerInstance(service2, "127.0.0.2", 90);          Thread.sleep(1000);          List instances = naming3.getAllInstances(service1);         Assert.assertEquals(1, instances.size());         Assert.assertEquals(service1, NamingUtils.getServiceName(instances.get(0).getServiceName()));         Assert.assertEquals(groupName, NamingUtils.getServiceName(NamingUtils.getGroupName(instances.get(0).getServiceName())));     }  }
  进一步考虑后发现该解决方案可能不太契合当前遇到的问题。公司目前的开发测试环境有很多个,并且不确定以后会不会继续增加。
  如果每增加一个环境,都需要修改一次公共服务的配置,并且重启一次公共服务,着实太麻烦了。倒不如反其道而行,让其他的服务器实现跨命名空间访问公共服务。
  02 跨命名空间访问
  针对实际问题查找资料时,我们找到了类似的参考分享《重写 Nacos 服务发现逻辑动态修改远程服务IP地址》。
  跟着博客思路看代码,笔者了解到服务发现的主要相关类是  NacosNamingService , NacosDiscoveryProperties , NacosDiscoveryAutoConfiguration 。
  然后,笔者将博客的示例代码复制过来,试着进行如下调试:  @Slf4j @Configuration @ConditionalOnNacosDiscoveryEnabled @ConditionalOnProperty(         name = {"spring.profiles.active"},         havingValue = "dev" ) @AutoConfigureBefore({NacosDiscoveryClientAutoConfiguration.class}) public class DevEnvironmentNacosDiscoveryClient {      @Bean     @ConditionalOnMissingBean     public NacosDiscoveryProperties nacosProperties() {         return new DevEnvironmentNacosDiscoveryProperties();     }      static class DevEnvironmentNacosDiscoveryProperties extends NacosDiscoveryProperties {          private NamingService namingService;          @Override         public NamingService namingServiceInstance() {             if (null != this.namingService) {                 return this.namingService;             } else {                 Properties properties = new Properties();                 properties.put("serverAddr", super.getServerAddr());                 properties.put("namespace", super.getNamespace());                 properties.put("com.alibaba.nacos.naming.log.filename", super.getLogName());                 if (super.getEndpoint().contains(":")) {                     int index = super.getEndpoint().indexOf(":");                     properties.put("endpoint", super.getEndpoint().substring(0, index));                     properties.put("endpointPort", super.getEndpoint().substring(index + 1));                 } else {                     properties.put("endpoint", super.getEndpoint());                 }                  properties.put("accessKey", super.getAccessKey());                 properties.put("secretKey", super.getSecretKey());                 properties.put("clusterName", super.getClusterName());                 properties.put("namingLoadCacheAtStart", super.getNamingLoadCacheAtStart());                  try {                     this.namingService = new DevEnvironmentNacosNamingService(properties);                 } catch (Exception var3) {                     log.error("create naming service error!properties={},e=,", this, var3);                     return null;                 }                  return this.namingService;             }         }      }      static class DevEnvironmentNacosNamingService extends NacosNamingService {          public DevEnvironmentNacosNamingService(Properties properties) {             super(properties);         }          @Override         public List selectInstances(String serviceName, List clusters, boolean healthy) throws NacosException {             List instances = super.selectInstances(serviceName, clusters, healthy);             instances.stream().forEach(instance -> instance.setIp("10.101.232.24"));             return instances;         }     }  }
  调试后发现博客提供的代码并不能满足笔者的需求,还得进一步深入探索。
  但幸运的是,调试过程发现 Nacos 服务发现的关键类是  com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery ,其中的关键方法是 getInstances()  和 getServices() ,即「返回指定服务 ID 的所有服务实例」和「获取所有服务的名称」。
  也就是说,对  getInstances()  方法进行重写肯定能实现本次目标——跨命名空间访问公共服务。 /**  * Return all instances for the given service.  * @param serviceId id of service  * @return list of instances  * @throws NacosException nacosException  */ public List getInstances(String serviceId) throws NacosException {         String group = discoveryProperties.getGroup();         List instances = discoveryProperties.namingServiceInstance()                         .selectInstances(serviceId, group, true);         return hostToServiceInstanceList(instances, serviceId); }  /**  * Return the names of all services.  * @return list of service names  * @throws NacosException nacosException  */ public List getServices() throws NacosException {         String group = discoveryProperties.getGroup();         ListView services = discoveryProperties.namingServiceInstance()                         .getServicesOfServer(1, Integer.MAX_VALUE, group);         return services.getData(); }
  03 最终解决思路及代码示例
  具体的解决方案思路大致如下:  生成一个共享配置类 NacosShareProperties ,用来配置共享公共服务的 namespace  和 group ; 重写配置类  NacosDiscoveryProperties  (新:NacosDiscoveryPropertiesV2 ),将新增的共享配置类作为属性放进该配置类,后续会用到; 重写服务发现类  NacosServiceDiscovery  (新:NacosServiceDiscoveryV2 ),这是最关键的逻辑; 重写自动配置类  NacosDiscoveryAutoConfiguration ,将自定义相关类比 Nacos 原生类更早的注入容器。
  最终代码中用到了一些工具类,可以自行补充完整。  /**  * 
  *  @description: 共享nacos属性  *  @author: rookie0peng  *  @date: 2022/8/29 15:22  *  
*/ @Configuration @ConfigurationProperties(prefix = "nacos.share") public class NacosShareProperties { private final Map> NAMESPACE_TO_GROUP_NAME_MAP = new ConcurrentHashMap<>(); /** * 共享nacos实体列表 */ private List entities; public List getEntities() { return entities; } public void setEntities(List entities) { this.entities = entities; } public Map> getNamespaceGroupMap() { safeStream(entities).filter(entity -> nonNull(entity) && nonNull(entity.getNamespace())) .forEach(entity -> { Set groupNames = NAMESPACE_TO_GROUP_NAME_MAP.computeIfAbsent(entity.getNamespace(), k -> new HashSet<>()); if (nonNull(entity.getGroupNames())) groupNames.addAll(entity.getGroupNames()); }); return new HashMap<>(NAMESPACE_TO_GROUP_NAME_MAP); } @Override public String toString() { return "NacosShareProperties{" + "entities=" + entities + "}"; } /** * 共享nacos实体 */ public static final class NacosShareEntity { /** * 命名空间 */ private String namespace; /** * 分组 */ private List groupNames; public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public List getGroupNames() { return groupNames; } public void setGroupNames(List groupNames) { this.groupNames = groupNames; } @Override public String toString() { return "NacosShareEntity{" + "namespace="" + namespace + """ + ", groupNames=" + groupNames + "}"; } } } /** * @description: naocs服务发现属性重写 * @author: rookie0peng * @date: 2022/8/30 1:19 */ public class NacosDiscoveryPropertiesV2 extends NacosDiscoveryProperties { private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryPropertiesV2.class); private final NacosShareProperties nacosShareProperties; private static final Map NAMESPACE_TO_NAMING_SERVICE_MAP = new ConcurrentHashMap<>(); public NacosDiscoveryPropertiesV2(NacosShareProperties nacosShareProperties) { super(); this.nacosShareProperties = nacosShareProperties; } public Map shareNamingServiceInstances() { if (!NAMESPACE_TO_NAMING_SERVICE_MAP.isEmpty()) { return new HashMap<>(NAMESPACE_TO_NAMING_SERVICE_MAP); } List entities = Optional.ofNullable(nacosShareProperties) .map(NacosShareProperties::getEntities).orElse(Collections.emptyList()); entities.stream().filter(entity -> nonNull(entity) && nonNull(entity.getNamespace())) .filter(PredicateUtil.distinctByKey(NacosShareProperties.NacosShareEntity::getNamespace)) .forEach(entity -> { try { NamingService namingService = NacosFactory.createNamingService(getNacosProperties(entity.getNamespace())); if (namingService != null) { NAMESPACE_TO_NAMING_SERVICE_MAP.put(entity.getNamespace(), namingService); } } catch (Exception e) { log.error("create naming service error! properties={}, e=", this, e); } }); return new HashMap<>(NAMESPACE_TO_NAMING_SERVICE_MAP); } private Properties getNacosProperties(String namespace) { Properties properties = new Properties(); properties.put(SERVER_ADDR, getServerAddr()); properties.put(USERNAME, Objects.toString(getUsername(), "")); properties.put(PASSWORD, Objects.toString(getPassword(), "")); properties.put(NAMESPACE, namespace); properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, getLogName()); String endpoint = getEndpoint(); if (endpoint.contains(":")) { int index = endpoint.indexOf(":"); properties.put(ENDPOINT, endpoint.substring(0, index)); properties.put(ENDPOINT_PORT, endpoint.substring(index + 1)); } else { properties.put(ENDPOINT, endpoint); } properties.put(ACCESS_KEY, getAccessKey()); properties.put(SECRET_KEY, getSecretKey()); properties.put(CLUSTER_NAME, getClusterName()); properties.put(NAMING_LOAD_CACHE_AT_START, getNamingLoadCacheAtStart()); // enrichNacosDiscoveryProperties(properties); return properties; } } /** * @description: naocs服务发现重写 * @author: rookie0peng * @date: 2022/8/30 1:10 */ public class NacosServiceDiscoveryV2 extends NacosServiceDiscovery { private final NacosDiscoveryPropertiesV2 discoveryProperties; private final NacosShareProperties nacosShareProperties; private final NacosServiceManager nacosServiceManager; public NacosServiceDiscoveryV2(NacosDiscoveryPropertiesV2 discoveryProperties, NacosShareProperties nacosShareProperties, NacosServiceManager nacosServiceManager) { super(discoveryProperties, nacosServiceManager); this.discoveryProperties = discoveryProperties; this.nacosShareProperties = nacosShareProperties; this.nacosServiceManager = nacosServiceManager; } /** * Return all instances for the given service. * @param serviceId id of service * @return list of instances * @throws NacosException nacosException */ public List getInstances(String serviceId) throws NacosException { String group = discoveryProperties.getGroup(); List instances = discoveryProperties.namingServiceInstance() .selectInstances(serviceId, group, true); if (isEmpty(instances)) { Map> namespaceGroupMap = nacosShareProperties.getNamespaceGroupMap(); Map namespace2NamingServiceMap = discoveryProperties.shareNamingServiceInstances(); for (Map.Entry entry : namespace2NamingServiceMap.entrySet()) { String namespace; NamingService namingService; if (isNull(namespace = entry.getKey()) || isNull(namingService = entry.getValue())) continue; Set groupNames = namespaceGroupMap.get(namespace); List shareInstances; if (isEmpty(groupNames)) { shareInstances = namingService.selectInstances(serviceId, group, true); if (nonEmpty(shareInstances)) break; } else { shareInstances = new ArrayList<>(); for (String groupName : groupNames) { List subShareInstances = namingService.selectInstances(serviceId, groupName, true); if (nonEmpty(subShareInstances)) { shareInstances.addAll(subShareInstances); } } } if (nonEmpty(shareInstances)) { instances = shareInstances; break; } } } return hostToServiceInstanceList(instances, serviceId); } /** * Return the names of all services. * @return list of service names * @throws NacosException nacosException */ public List getServices() throws NacosException { String group = discoveryProperties.getGroup(); ListView services = discoveryProperties.namingServiceInstance() .getServicesOfServer(1, Integer.MAX_VALUE, group); return services.getData(); } public static List hostToServiceInstanceList( List instances, String serviceId) { List result = new ArrayList<>(instances.size()); for (Instance instance : instances) { ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId); if (serviceInstance != null) { result.add(serviceInstance); } } return result; } public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) { if (instance == null || !instance.isEnabled() || !instance.isHealthy()) { return null; } NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); nacosServiceInstance.setHost(instance.getIp()); nacosServiceInstance.setPort(instance.getPort()); nacosServiceInstance.setServiceId(serviceId); Map metadata = new HashMap<>(); metadata.put("nacos.instanceId", instance.getInstanceId()); metadata.put("nacos.weight", instance.getWeight() + ""); metadata.put("nacos.healthy", instance.isHealthy() + ""); metadata.put("nacos.cluster", instance.getClusterName() + ""); metadata.putAll(instance.getMetadata()); nacosServiceInstance.setMetadata(metadata); if (metadata.containsKey("secure")) { boolean secure = Boolean.parseBoolean(metadata.get("secure")); nacosServiceInstance.setSecure(secure); } return nacosServiceInstance; } private NamingService namingService() { return nacosServiceManager .getNamingService(discoveryProperties.getNacosProperties()); } } /** * @description: 重写nacos服务发现的自动配置 * @author: rookie0peng * @date: 2022/8/30 1:08 */ @Configuration(proxyBeanMethods = false) @ConditionalOnDiscoveryEnabled @ConditionalOnNacosDiscoveryEnabled @AutoConfigureBefore({NacosDiscoveryAutoConfiguration.class}) public class NacosDiscoveryAutoConfigurationV2 { @Bean @ConditionalOnMissingBean public NacosDiscoveryPropertiesV2 nacosProperties(NacosShareProperties nacosShareProperties) { return new NacosDiscoveryPropertiesV2(nacosShareProperties); } @Bean @ConditionalOnMissingBean public NacosServiceDiscovery nacosServiceDiscovery( NacosDiscoveryPropertiesV2 discoveryPropertiesV2, NacosShareProperties nacosShareProperties, NacosServiceManager nacosServiceManager ) { return new NacosServiceDiscoveryV2(discoveryPropertiesV2, nacosShareProperties, nacosServiceManager); } }   本以为问题到这就结束了,但最后自测时发现程序根本不走 Nacos 的服务发现逻辑,而是执行 Ribbon 的负载均衡逻辑com.netflix.loadbalancer.AbstractLoadBalancerRule 。   不过实现类是 com.alibaba.cloud.nacos.ribbon.NacosRule ,继续基于 NacosRule 重写负载均衡。 /** * @description: 共享nacos命名空间规则 * @author: rookie0peng * @date: 2022/8/31 2:04 */ public class ShareNacosNamespaceRule extends AbstractLoadBalancerRule { private static final Logger LOGGER = LoggerFactory.getLogger(ShareNacosNamespaceRule.class); @Autowired private NacosDiscoveryPropertiesV2 nacosDiscoveryPropertiesV2; @Autowired private NacosShareProperties nacosShareProperties; /** * 重写choose方法 * * @param key * @return */ @SneakyThrows @Override public Server choose(Object key) { try { String clusterName = this.nacosDiscoveryPropertiesV2.getClusterName(); DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer(); String name = loadBalancer.getName(); NamingService namingService = nacosDiscoveryPropertiesV2 .namingServiceInstance(); List instances = namingService.selectInstances(name, true); if (CollectionUtils.isEmpty(instances)) { LOGGER.warn("no instance in service {}, then to get share service"s instance", name); List shareNamingService = this.getShareNamingService(name); if (nonEmpty(shareNamingService)) instances = shareNamingService; else return null; } List instancesToChoose = instances; if (org.apache.commons.lang3.StringUtils.isNotBlank(clusterName)) { List sameClusterInstances = instances.stream() .filter(instance -> Objects.equals(clusterName, instance.getClusterName())) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(sameClusterInstances)) { instancesToChoose = sameClusterInstances; } else { LOGGER.warn( "A cross-cluster call occurs,name = {}, clusterName = {}, instance = {}", name, clusterName, instances); } } Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose); return new NacosServer(instance); } catch (Exception e) { LOGGER.warn("NacosRule error", e); return null; } } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } private List getShareNamingService(String serviceId) throws NacosException { List instances = Collections.emptyList(); Map> namespaceGroupMap = nacosShareProperties.getNamespaceGroupMap(); Map namespace2NamingServiceMap = nacosDiscoveryPropertiesV2.shareNamingServiceInstances(); for (Map.Entry entry : namespace2NamingServiceMap.entrySet()) { String namespace; NamingService namingService; if (isNull(namespace = entry.getKey()) || isNull(namingService = entry.getValue())) continue; Set groupNames = namespaceGroupMap.get(namespace); List shareInstances; if (isEmpty(groupNames)) { shareInstances = namingService.selectInstances(serviceId, true); if (nonEmpty(shareInstances)) break; } else { shareInstances = new ArrayList<>(); for (String groupName : groupNames) { List subShareInstances = namingService.selectInstances(serviceId, groupName, true); if (nonEmpty(subShareInstances)) { shareInstances.addAll(subShareInstances); } } } if (nonEmpty(shareInstances)) { instances = shareInstances; break; } } return instances; } }   至此问题得以解决。   在 Nacos 上配置好共享 namespace 和 group 后,就能够进行跨命名空间访问了。 # nacos共享命名空间配置 示例 nacos.share.entities[0].namespace=e6ed2017-3ed6-4d9b-824a-db626424fc7b nacos.share.entities[0].groupNames[0]=DEFAULT_GROUP # 指定服务使用共享的负载均衡规则,service-id是注册到nacos上的服务id,ShareNacosNamespaceRule需要写全限定名 service-id.ribbon.NFLoadBalancerRuleClassName=***.***.***.ShareNacosNamespaceRule   注意:如果 Java 项目的 nacos discovery 版本用的是 2021.1 ,则不需要重写 Ribbon 的负载均衡类,因为该版本的 Nacos 不依赖 Ribbon。   2.2.1.RELEASE 版本 的 nacos discovery 依赖 Ribbon.   2021.1 版本 的 nacos discovery 不依赖 Ribbon。   四、总结   为了达到共享命名空间的预期,构思、查找资料、实现逻辑、调试,前后一共花费 4 天时间。成就感满满的同时,笔者也发现该功能仍存在共享服务缓存等可优化空间,留待后续实现。

一个被寄予厚望的粒子假说,被否决了一个谜题的终结我们生活在一个由粒子所构成的世界之中。在现代粒子物理学中,所有已知的基本粒子及其相互作用,都是由粒子物理学的标准模型描述的。在标准模型中,中微子吸引了许多的关注。目前为卧室影院补上缺失的超重低音!SonosSubMini入手试听这两天终于入手了Sonos新发布的高性能无线低音炮SubMini,看起来这个春节长假我又多了一个宅在家里的理由。作为一名Sonos产品的忠实用户,我从2012年起就在家里使用他们的全新模块化设计理念,联想ThinkPadStack10000mAh移动电源拆解前言联想在2016年推出了一套ThinkPadStack功能模块,包括移动电源移动硬盘蓝牙音箱无线路由器和投影模块组合。模块之间支持自由组合,实现功能上的扩展。充电头网拿到了其中的滴滴被约谈后率先行动,起步价与里程费上涨,网约车迎来涨价潮近日,有关部门约谈了滴滴等十五家出行平台,内容包括了春运期间出行安全以及网约车运价问题。网约车司机都知道,现在网约车市场内卷严重,运价低的情况已经不是一天两天了。大家原本只是希望新一段关系应该结束了的8个信号武志红老师曾说一段好的关系,你会感到自我被滋养,越来越鲜活喜欢自己。而一段坏的关系,则让你感到自我被破坏,难以接纳自己,让人感觉越来萎缩。一个人能量状态的好坏,藏在他所处的关系中,政企携手,让专精特新小巨人澎湃大能量专精特新企业是强链补链固链的生力军,也是经济活力的重要载体。目前,江苏省已有国家级专精特新小巨人企业424家。如何抢占产业链发展的重要节点,让更多小巨人释放出大能量?完善培育体系,梦想在前方,奋进在陪上人,总是需要脚踏实地,总是需要仰望星空!生活看似波澜不惊,实则暗流涌动。有时候,努力了很久,未必就能看到希望。有时候,一不小心的歪打误撞,就能推开一扇成功的大门。胸中有爱,眼里有光忘不了的泉(散文)忘不了一眼泉!大自然的迷人馈赠,游也游不尽,赏也赏不完,何以独钟于那泉?泉类万万干,出名的千千万,何以总忘不了那眼泉?那是一眼普通得再不能普通的泉山道弯弯。褐黄色的山峰,发芽似的,五十岁以后,为自己而活人生过半,恍然间明白了,活着就是一个过程。几十年,最多不过百年。大多数人的前半生都是稀里糊涂。人生的遗憾在边走边爱的日子里留下。没有一个人的人生是完美无缺的,遗憾和无奈都是在所难免沙与沫文摘精选沙和水沫会被吹到很远,海和海滩也会存在1。仅在昨天,我还自以为是碎片,不住颤抖,杂乱无章,运行在生命的苍穹间。现在我已知道,我就是苍穹,生命是在我心中运动着的排列有序的碎片。2。将我聚集起来的太阳,却不能把我分解开来。外媒ASML担心的问题出现了大家都知道,ASML作为全球半导体制作设备的供应商,旗下光刻机对全球芯片市场的重要性几乎是无可替代的,甚至可以是实现100垄断的效果。但ASML由于光刻机制作材料与零件并非全自产的
0比44惨败!女足出现尴尬比分央视发声,网友中国女足复兴难中国女足被称为铿锵玫瑰,这支球队曾经给大家带来过非常多的感动,在亚特兰大奥运会和99年的女足世界杯上,中国女足都获得了亚军的好成绩,虽然没有能够拿下世界冠军,但是在很多人心目中,中大家都在看LPL赛事,网友们说出电竞椅的真实体验感受一封网友电竞椅的真实感受的表述最近同事们都在讨论LPLEPLKPL的赛事,他们下班或周末都会久坐沉迷这些游戏中,在他们的讨论中令我想起了初中高中时候那段游戏记忆,什么梦幻西游穿越火借拍戏之名行咸猪手被批,娱乐圈的不雅之举其实不止于此油腻,俗套脱离现实,不能容忍。人民网的一篇短评,将最近正在热播的新剧东八区的先生们,推上了舆论高潮。要知道,人民网这样的官媒,是很少去评论娱乐剧的。而此次,在人民网的评论中,不仅用不止是袭胸,娱乐圈中层出不穷的咸猪手,让女演员们苦不堪言近日,由张翰担任编剧制作人且精心打磨十年的诚意之作东八区的先生们因为油腻的台词尴尬的镜头被观众们集体嫌弃。其中,男演员拉扯女演员内衣的镜头,被无数网友吐槽,这不就是妥妥的职场X骚扰借拍戏之名行咸猪手被批,娱乐圈的不雅之举其实不止于此油腻,俗套脱离现实,不能容忍。人民网的一篇短评,将最近正在热播的新剧东八区的先生们,推上了舆论高潮。要知道,人民网这样的官媒,是很少去评论娱乐剧的。而此次,在人民网的评论中,不仅用勇士消息克莱放飞自我,或签10届全明星,一哥怒怼名嘴北京时间9月4日,远在大洋彼岸的金州勇士传来了3条消息,一起来看看吧。克莱放飞自我昨日,勇士球星克莱汤普森更新了ins,晒出了一段自己在游艇上热舞的视频。视频中,汤普森头戴黑色礼帽生不逢时的内马尔,还能硬刚姆巴佩和哈兰德吗?2013年,年仅21岁,但已拿了两次南美足球先生的天才少年内马尔,加盟巴塞罗那的强烈目标就是接班梅西,成为巴萨乃至足坛的王者。内少想拿金球奖在接下来的赛季中,内马尔逐渐兑现了他的足6场造16球也没人要?巴黎关窗前兜售内马尔瓜帅拒签他搭档哈兰德北京时间9月3日,据西班牙媒体马卡报透露,在今夏转会市场关闭前的最后时刻,巴黎圣日耳曼俱乐部曾向曼城推销过内马尔。大巴黎高层认为,送走经常会在更衣室制造紧张气氛的内马尔有利于俱乐部2023款别克君威上市,价格不变配置微调,售价19。6821。08万元日前,上汽通用别克品牌旗下新车2023款别克君威正式上市,新车继续提供两款配置车型可选,官方售价19。6821。08万元。新车外观及内饰沿用了老款车型的造型设计,仅在细微配置上进行00!青岛海牛输球优势不再,中甲争三进入白热化阶段北京时间9月15日下午,中甲第21轮开打青岛海牛VS石家庄功夫。上半场,韦尼西奥破门。下半场,和巍两黄变一红。最终,青岛海牛01输给石家庄功夫。在目前的中甲积分榜上,青岛海牛以43马龙,有新身份了今天是研究生马龙据人民日报体育消息,近日,北京体育大学开学典礼上,马龙作为研究生新生代表发言。由于备战世乒赛,马龙不能到现场,便通过视频向同学们表示了欢迎。截图来源网友山川去何岁北