前言

  Nacos最近项目一直在使用,其简单灵活,支持更细粒度的命令空间,分组等为麻烦复杂的环境切换提供了方便;同时也很好支持动态路由的配置,只需要简单的几步即可。在国产的注册中心、配置中心中比较突出,容易上手,本文通过gateway、nacos-consumer、nacos-provider三个简单模块来展示:Nacos下动态路由配置。

  


一、Nacos环境准备

1、启动Nacos配置中心并创建路由配置

具体的Nacos怎么配置就不介绍了,可以参考阿里巴巴的官方介绍,这里通过windows直接本地启动开启单机模式,登录Nacos Console,创建dev的namespace,在dev下的默认分组下创建gateway-router的dataId

gateway-router的主要初始化配置如下:关于gateway的组成(id,order、predicates断言,uri)这里就不详细说明的了,可以自行百度下

[{
"id": "consumer-router",
"order": 0,
"predicates": [{
"args": {
"pattern": "/consume/**"
},
"name": "Path"
}],
"uri": "lb://nacos-consumer"
},{
"id": "provider-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/provide/**"
},
"name": "Path"
}],
"uri": "lb://nacos-provider"
}]

2、连接Nacos配置中心

通常在项目中配置“配置中心”往往都是在bootstrap.propertis(yaml)中配置,这样才能保证项目中路由配置从Nacos Config中读取。

# nacos配置中心配置建议在bootstrap.properties中配置
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#spring.cloud.nacos.config.file-extension=properties
# 配置中心的命名空间:dev 的命名空间(环境)
spring.cloud.nacos.config.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea

Application启动类中增加注解@EnableDiscoveryClient,才能保证连接到Nacos Config

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication
{
public static void main( String[] args )
{
SpringApplication.run(GatewayApplication.class, args);
}
}

二、项目构建

1、项目结构

创建简单的spring boot多模块结构,推荐使用idea创建

1)Nacos父模块:

<groupId>com.springcloud</groupId>
<artifactId>nacos</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>nacos</name>
<description>Nacos Demo</description>

首先pom文件引入Spring Cloud Alibaba Nacos组件:注册中心nacos-discovery与配置中心nacos-config

 <!--nacos 客户端 注册中心-->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  <version>${alibaba-nacos.version}</version>
</dependency>
<!--nacos 客户端 配置中心-->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  <version>${alibaba-nacos.version}</version>
</dependency>

其次再引入Spring Cloud相关组件依赖

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

其它组件依赖引入(修正:如果引入了nacos-api相关的JSON依赖,那么fastjson就不需要再引入了,否则可能冲突):

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

注意,这里有个坑,spring cloud gateway使用的web框架为webflux,和springMVC不兼容。所以不要引入(修正:只有gateway服务不用引入springMVC,其他需要引入)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2)三个子模块:gateway、nacos-consumer、nacos-provider

<modules>
  <module>nacos-provider</module>
  <module>nacos-consumer</module>
  <module>gateway</module>
</modules>

结构截图如下所示:

3)三个服务的端口分别为:

  nacos-consume:6001

  nacos-provider:6002

  gateway:6003

4)服务架构如下:

                    

2、编写测试代码

(1)在gateway模块中主要实现以下功能:

第一,从Nacos配置中心中加载动态路由的相关配置,就需要读取Nacos的命名空间namespace,通过dataId获取配置

/**
* 路由类配置
*/
@Configuration
public class GatewayConfig {
public static final long DEFAULT_TIMEOUT = 30000; public static String NACOS_SERVER_ADDR; public static String NACOS_NAMESPACE; public static String NACOS_ROUTE_DATA_ID; public static String NACOS_ROUTE_GROUP; @Value("${spring.cloud.nacos.discovery.server-addr}")
public void setNacosServerAddr(String nacosServerAddr){
NACOS_SERVER_ADDR = nacosServerAddr;
} @Value("${spring.cloud.nacos.discovery.namespace}")
public void setNacosNamespace(String nacosNamespace){
NACOS_NAMESPACE = nacosNamespace;
} @Value("${nacos.gateway.route.config.data-id}")
public void setNacosRouteDataId(String nacosRouteDataId){
NACOS_ROUTE_DATA_ID = nacosRouteDataId;
} @Value("${nacos.gateway.route.config.group}")
public void setNacosRouteGroup(String nacosRouteGroup){
NACOS_ROUTE_GROUP = nacosRouteGroup;
} }

properties配置关于Nacos下读取gateway-router的配置:

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea
nacos.gateway.route.config.data-id=gateway-router
nacos.gateway.route.config.group=DEFAULT_GROUP

第二,初始化路由,监听动态路由配置的数据源变化;

/**
*
* 通过nacos下发动态路由配置,监听Nacos中gateway-route配置
*
*/
@Component
@Slf4j
@DependsOn({"gatewayConfig"}) // 依赖于gatewayConfig bean
public class DynamicRouteServiceImplByNacos { @Autowired
private DynamicRouteServiceImpl dynamicRouteService; private ConfigService configService; @PostConstruct
public void init() {
log.info("gateway route init...");
try{
configService = initConfigService();
if(configService == null){
log.warn("initConfigService fail");
return;
}
String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT);
log.info("获取网关当前配置:\r\n{}",configInfo);
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
for(RouteDefinition definition : definitionList){
log.info("update route : {}",definition.toString());
dynamicRouteService.add(definition);
}
} catch (Exception e) {
log.error("初始化网关路由时发生错误",e);
}
dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,GatewayConfig.NACOS_ROUTE_GROUP);
} /**
* 监听Nacos下发的动态路由配置
* @param dataId
* @param group
*/
public void dynamicRouteByNacosListener (String dataId, String group){
try {
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("进行网关更新:\n\r{}",configInfo);
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
for(RouteDefinition definition : definitionList){
log.info("update route : {}",definition.toString());
dynamicRouteService.update(definition);
}
}
@Override
public Executor getExecutor() {
log.info("getExecutor\n\r");
return null;
}
});
} catch (NacosException e) {
log.error("从nacos接收动态路由配置出错!!!",e);
}
} /**
* 初始化网关路由 nacos config
* @return
*/
private ConfigService initConfigService(){
try{
Properties properties = new Properties();
properties.setProperty("serverAddr",GatewayConfig.NACOS_SERVER_ADDR);
properties.setProperty("namespace",GatewayConfig.NACOS_NAMESPACE);
return configService= NacosFactory.createConfigService(properties);
} catch (Exception e) {
log.error("初始化网关路由时发生错误",e);
return null;
}
}
}

第三,刷新最新的动态路由变化,实现动态增删改路由

/**
* 动态更新路由网关service
* 1)实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
* 2)提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
*/
@Slf4j
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter; /**
* 发布事件
*/
@Autowired
private ApplicationEventPublisher publisher; @Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
} /**
* 删除路由
* @param id
* @return
*/
public String delete(String id) {
try {
log.info("gateway delete route id {}",id);
this.routeDefinitionWriter.delete(Mono.just(id));
return "delete success";
} catch (Exception e) {
return "delete fail";
}
}
/**
* 更新路由
* @param definition
* @return
*/
public String update(RouteDefinition definition) {
try {
log.info("gateway update route {}",definition);
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception e) {
return "update fail,not find route routeId: "+definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
} /**
* 增加路由
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
log.info("gateway add route {}",definition);
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
}

(2)在consumer创建ConsumeController:通过访问gateway网关/consume/sayHello/{name}("pattern": "/consume/**"),跳转至nacos-consumer服务("uri": "lb://nacos-consumer"),

@RequestMapping("/consume/")
@Slf4j
public class ConsumeController { @GetMapping("/sayHello/{name}")
public String sayHello(@PathVariable("name") String name){
log.info("I'm calling nacos-consumer service by dynamic gateway...");
return name + " Hi~, I'm from nacos-consumer";
}
}

(3)在provider创建ProviderController:通过访问gateway网关/provide/sayHello/{name}("pattern": "/provide/**"),跳转至nacos-provider服务("uri": "lb://nacos-provider")

@RestController
@RequestMapping("/provide/")
@Slf4j
public class ProviderController { @GetMapping("/sayHello/{name}")
public String sayHello(@PathVariable("name") String name){
log.info("I'm calling nacos-provider service by dynamic gateway...");
return name + " Hi~, I'm from nacos-provider";
}
}

三、测试动态网关配置

1、启动服务,观察注册中心

分别启动gateway、nacos-consumer、nacos-provider三个服务,观察是否已经在Nacos上正确注册

注意:需要指定注册中心的namespace为dev的空间,即spring.cloud.nacos.discovery.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea

2、访问网关,观察服务日志

(1)查看gateway服务的初始化启动日志:会发现可以正常从Nacos获取配置gateway-router网关配置文件内容,并进行正确路由加载...

2020-05-10 14:33:44.557  INFO 1272 --- [           main] c.g.r.DynamicRouteServiceImplByNacos     : gateway route init...
2020-05-10 14:33:44.578 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : 获取网关当前配置:
[{
"id": "consumer-router",
"order": 0,
"predicates": [{
"args": {
"pattern": "/consume/**"
},
"name": "Path"
}],
"uri": "lb://nacos-consumer"
},{
"id": "provider-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/provide/**"
},
"name": "Path"
}],
"uri": "lb://nacos-provider"
}]
2020-05-10 14:33:44.691 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='consumer-router', predicates=[PredicateDefinition{name='Path', args={pattern=/consume/**}}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}}
2020-05-10 14:33:44.691 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition{id='consumer-router', predicates=[PredicateDefinition{name='Path', args={pattern=/consume/**}}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}}
2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [After]
2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Before]
2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Between]
2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Cookie]
2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Header]
2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Host]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Method]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Path]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Query]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [ReadBodyPredicateFactory]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [RemoteAddr]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Weight]
2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [CloudFoundryRouteService]
2020-05-10 14:33:45.335 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='provider-router', predicates=[PredicateDefinition{name='Path', args={pattern=/provide/**}}], filters=[], uri=lb://nacos-provider, order=2, metadata={}}
2020-05-10 14:33:45.335 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition{id='provider-router', predicates=[PredicateDefinition{name='Path', args={pattern=/provide/**}}], filters=[], uri=lb://nacos-provider, order=2, metadata={}}
2020-05-10 14:33:45.336 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='github-router', predicates=[PredicateDefinition{name='Path', args={pattern=/github}}], filters=[], uri=https://github.com, order=3, metadata={}}
2020-05-10 14:33:45.336 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition{id='github-router', predicates=[PredicateDefinition{name='Path', args={pattern=/github}}], filters=[], uri=https://github.com, order=3, metadata={}}

但这只能说明是初始化静态路由,下面我们改变gateway-router网关配置内容,追加github-router路由

[{
"id": "consumer-router",
"order": 0,
"predicates": [{
"args": {
"pattern": "/consume/**"
},
"name": "Path"
}],
"uri": "lb://nacos-consumer"
},{
"id": "provider-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/provide/**"
},
"name": "Path"
}],
"uri": "lb://nacos-provider"
},{
"id": "github-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/github/**"
},
"name": "Path"
}],
"uri": "https://github.com"
}]

之后点击发布更新路由配置

观察gateway服务日志,有没有监听,并且进行正确的路由更新:如下日志所示,最新路由配置立马被打印,并且进行正确路由更新

2020-05-10 14:42:27.576  INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos     : 进行网关更新:

[{
"id": "consumer-router",
"order": 0,
"predicates": [{
"args": {
"pattern": "/consume/**"
},
"name": "Path"
}],
"uri": "lb://nacos-consumer"
},{
"id": "provider-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/provide/**"
},
"name": "Path"
}],
"uri": "lb://nacos-provider"
},{
"id": "github-router",
"order": 2,
"predicates": [{
"args": {
"pattern": "/github/**"
},
"name": "Path"
}],
"uri": "https://github.com"
}]
2020-05-10 14:42:27.576 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='consumer-router', predicates=[PredicateDefinition{name='Path', args={pattern=/consume/**}}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}}
2020-05-10 14:42:27.576 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition{id='consumer-router', predicates=[PredicateDefinition{name='Path', args={pattern=/consume/**}}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}}
2020-05-10 14:42:27.578 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='provider-router', predicates=[PredicateDefinition{name='Path', args={pattern=/provide/**}}], filters=[], uri=lb://nacos-provider, order=2, metadata={}}
2020-05-10 14:42:27.578 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition{id='provider-router', predicates=[PredicateDefinition{name='Path', args={pattern=/provide/**}}], filters=[], uri=lb://nacos-provider, order=2, metadata={}}
2020-05-10 14:42:27.580 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition{id='github-router', predicates=[PredicateDefinition{name='Path', args={pattern=/github/**}}], filters=[], uri=https://github.com, order=2, metadata={}}
2020-05-10 14:42:27.580 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition{id='github-router', predicates=[PredicateDefinition{name='Path', args={pattern=/github/**}}], filters=[], uri=https://github.com, order=2, metadata={}}

其实,还有办法可以知道我们的gateway服务有没有监听Nacos的gateway-router配置,那就是在Nacos Console--->监听查询----->选择配置---->输入配置文件的namespace与Group: 可以发现我本地IP地址127.0.0.1对配置文件gateway-router进行了监听

(2)访问gateway网关服务:http://localhost:6003/consume/sayHello/nacos

  

查看consumer服务日志:

2020-05-10 14:55:07.257  INFO 6552 --- [nio-6001-exec-2] c.n.c.controller.ConsumeController       : I'm calling nacos-consumer service by dynamic gateway...

发现跳转至consumer服务,并且访问了consumer服务的CosnumerController

(3)访问gateway网关服务:http://localhost:6003/provider/sayHello/nacos

  

查看provider服务日志:

2020-05-10 14:56:56.144  INFO 10024 --- [nio-6002-exec-1] c.n.p.controller.ProviderController      : I'm calling nacos-provider service by dynamic gateway...

发现跳转至consumer服务,并且访问了provider服务的ProviderController

(4)访问访问gateway网关服务:http://localhost:6003/github,正确跳转至github页面

四、总结

  1)Spring Cloud Gateway作用不光只是简单的跳转重定向,还可以实现用户的验证登录,解决跨域,日志拦截,权限控制,限流,熔断,负载均衡,黑名单和白名单机制等。是微服务架构不二的选择

  2)Nacos的配置中心支持动态获取配置文件,可以将一些全局的经常变更的配置文件放在Nacos下,需要到微服务自行获取。

Nacos下动态路由配置的更多相关文章

  1. AIX 环境下动态路由

    IBM AIX v5.3操作系统环境下动态路由配置如下: 1,用命令lssrc -S routed和lssrc -S gated分别检查routed和gated子系统是是活动状态.如果这两个子系统为活 ...

  2. vue动态路由配置,vue路由传参

    动态路由: 当我们很多个页面或者组件都要被很多次重复利用的时候,我们的路由都指向同一个组件,这时候从不同组件进入一个"共用"的组件,并且还要传参数,渲染不同的数据 这就要用到动态路 ...

  3. 从壹开始 [vueAdmin后台] 之三 || 动态路由配置 & 项目快速开发

    回顾 今天VS 2019正式发布,实验一波,你安装了么?Blog.Core 预计今天会升级到 Core 3.0 版本. 哈喽大家周三好!本来今天呢要写 Id4 了,但是写到了一半,突然有人问到了关于 ...

  4. 交换路由中期测验20181226(动态路由配置与重分发、NAT转换、ACL访问控制列表)

    测试拓扑: 接口配置信息 HostName 接口 IP地址 网关 Server 0 Fa0 172.16.15.1/24 172.16.15.254 Server 1 Fa0 100.2.15.200 ...

  5. Cisco动态路由配置

    前言: 学完静态路由配置,该学动态路由.所以 学习完后来做终结. 准备: PC:192.168.1.10 R1:fa0/0 192.168.1.1 fa0/1 1.1.12.1 R2: fa0/0 1 ...

  6. Linux系统多网卡环境下的路由配置

    Linux下路由配置命令 1. 添加主机路由 route add -host 192.168.1.11 dev eth0 route add -host 192.168.1.12 gw 192.168 ...

  7. Cisco基础(二):三层交换vlan间通信、多交换机vlan间通信、三层交换配置路由、RIP动态路由配置、三层交换配置RIP动态路由

    一.三层交换vlan间通信 目标: VLAN实现了广播域的隔离,同时也将VLAN间的通信隔离了.三层交换技术使得VLAN间可以通信. 通过三层交换实现VLAN间通信 方案: 为了解决了传统路由器低速. ...

  8. C# MVC 项目下的路由配置-RouteConfig

    1. 设置备份全局路径下的路由 目的,我们在网站中域名后面输入参数,可以跳转到相应的controller,例如:www.innovsys.cn/dd.直后端直接跳转到controller,获取dd参数 ...

  9. Mac下持久化路由配置

    缘由 mac 下有个小命令,networksetup,之前电脑装了IKEv2 的VPN,每天能正常FQ,由于所有流量都走了VPN隧道,导致了公司内部的其它网络无法访问得到,必须每次的来回拨VPN,断V ...

随机推荐

  1. 性能测试-pidstat 问题定位分析

    pidstat 概述 pidstat是sysstat工具的一个命令,用于监控全部或指定进程的cpu.内存.线程.设备IO等系统资源的占用情况.pidstat首次运行时显示自系统启动开始的各项统计信息, ...

  2. 4.加密与token(node+express)

    一. 敏感数据加密1.安装并引入中间件     npm install utility     const utils = require('utility')2.加密方法     function ...

  3. Acid靶机渗透

    Acid渗透靶机实战 攻击机:kali 192.168.41.147 靶机: acid 192.168.41.149 信息收集 ip发现 开启Acid靶机,通过nmap进行局域网存火主机扫描.![]( ...

  4. 不借助多余参数也可交换两个参数(c++,swap函数)

    利用a^a=0异或属性 [示例代码] #include<stdio.h> void data_swap(int &a,int &b){ a = a ^ b; b = a ^ ...

  5. 使用NLP从文章中自动提取关键字

    背景 在研究和新闻文章中,关键词构成了一个重要的组成部分,因为它们提供了文章内容的简洁表示.关键词在从信息检索系统,书目数据库和搜索引擎优化中定位文章方面也起着至关重要的作用.关键词还有助于将文章分类 ...

  6. blink测试技术介绍

    引言: flink是面向数据流处理和批处理的分布式开源计算框架.2016年阿里巴巴引入flink框架,改造为blink,将其运用到搜索及推荐的离线实时计算中,成功解决了搜索.推荐实时大数据量计算的痛点 ...

  7. 用pytorch做手写数字识别,识别l率达97.8%

    pytorch做手写数字识别 效果如下: 工程目录如下 第一步  数据获取 下载MNIST库,这个库在网上,执行下面代码自动下载到当前data文件夹下 from torchvision.dataset ...

  8. automake autoconf 使用详解

    本文地址: http://www.laruence.com/2009/11/18/1154.html 文章转自: http://www.linuxcomputer.cn/ 作为Linux下的程序开发人 ...

  9. SpringCloudAlibaba实战教程系列

    一.简介 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案.此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开 ...

  10. Comparable 接口与Comparator的使用的对比

    package com.yhqtv.java; import org.junit.Test; import java.util.Arrays; import java.util.Comparator; ...