Spring boot 整合grpc 运用

文章目录

    • GRPC基础概念:
    • Protocol Buffers:
      • proto 基础语法:
        • 调用类型:
    • Spring boot 整合 grpc
      • 项目结构:
      • 整合代码:
        • 父 pom
        • proto 模块
        • 服务端:
        • 客户端:
        • 实际调用:
      • 原生集成

GRPC基础概念:

  • GRPC是google开源的一个高性能、跨语言的RPC框架,基于HTTP2协议,基于protobuf 3.x,基于Netty 4.x.

Protocol Buffers:

  • 一个跨语言、跨平台的具有可扩展机制的序列化数据工具。也就是说,我在ubuntu下用python语言序列化一个对象,并使用http协议传输到使用java语言的android客户端,java使用对用的代码工具进行反序列化,也可以得到对应的对象
    1

proto 基础语法:

//指定proto3语法
syntax = "proto3";
//指定作用域
package xxx;
//java_multiple_files = true; 表示在生成Java代码时,每个`.proto`文件都会生成一个独立的Java文件
//声明 rpc 服务接口
//关键字: service 声明需要生成的服务接口"类"
service Greeter {// 关键字: rpc 声明服务方法,包括方法名、请求消息(请求体)、相应消息(响应体)rpc SayHello(HelloRequest) returns (HelloResponse);
}
//声明请求、响应消息
//关键字: message 声明请求体和响应体
message HelloRequest {//标识号 1//编号的范围为1 ~ 536,870,911(2^29-1),其中19000~19999不可用。因为Protobuf协议的实现过程中对预留了这些编号string name = 1;//表示一个人有多个号码repeated string phone = 3;
}message HelloResponse {string message = 1;
}
调用类型:
  • Unary RPC 一元RPC调用,也叫简单RPC调用

    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • 【服务端 Server Stream RPC】流式RPC. 客户端向服务端发送单个请求,服务端以流的方式返回一系列消息。客户端从流中读取消息,直到没有更多的消息。当然,返回的消息当然不是乱序的,gRPC保证单个请求中的消息顺序

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • 【客户端 Client Stream RPC】流式RPC调用。客户端向服务端请求一系列的消息,一旦客户端完成消息写入,就会等待服务端读取所有消息并处理它们。gRPC同样会保证单个请求中消息的顺序性

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • 【双向流式调用 Bidirectional Streaming RPC】就是客户端和服务端均以流的方式进行读写消息。这两个流式完全独立的,因此,服务端和客户端可以按照他们喜欢的方式写入和读取流。比如:服务端可以在等待所有的客户端消息发送到后,再处理;也可以交替读取请求、写入响应信息等。当然,每个流中的消息顺序是可以保证的。

    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

    Channels通道

    gRPC通道提供了一条链接到指定主机和端口号的服务端的链接。他在创建客户端stub的时候使用。客户端可以指定通道参数来修改gRPC的默认行为,例如:打开或者关闭消息压缩。一个通道是有连接和空闲两个状态的

mvn 插件整合,proto编译,生成代码

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><!-- 生成插件 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!--设置grpc生成代码到指定路径--><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!--生成代码前是否清空目录--><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions></build>

在这里插入图片描述

Spring boot 整合 grpc

大致流程:
1

项目结构:

在这里插入图片描述

整合代码:

父 pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><name>grpc-demo</name><modules><module>grpc-server</module><module>grpc-client</module><module>grpc-proto</module></modules><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><grpc.version>2.15.0.RELEASE</grpc.version></properties><!-- 通用依赖 --><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
proto 模块
syntax = "proto3";package com.ht.meta;
// 生成类的包名
option java_multiple_files = true;
// 生成代码位置
option java_package = "com.meta";
// 定义的所有消息、枚举和服务生成对应的多个类文件,而不是以内部类的形式出现
option java_outer_classname = "HtMetaInfoSyncProto";service HtMetaInfoSyncService {rpc syncMeta (HtMetaSyncRequest) returns (HtMetaSyncResponse) {}
}//同步类型
enum SyncType {ADD  = 0; // 新增DEL  = 1; // 删除EDIT = 2; // 修改
}//同步Request
message HtMetaSyncRequest {//json内容string syncJson = 1;//同步类型SyncType syncType = 2;
}//响应Response
message HtMetaSyncResponse {//响应码string code = 1;//提示string msg = 2;
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-proto</artifactId><packaging>jar</packaging><name>grpc-proto</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><!-- 生成插件 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!--设置grpc生成代码到指定路径--><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!--生成代码前是否清空目录--><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions></build></project>
服务端:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-server</artifactId><packaging>jar</packaging><name>grpc-server</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency></dependencies></project>
server:port: 8080spring:application:name: spring-boot-grpc-server# gRPC有关的配置,这里只需要配置服务端口号
grpc:server:port: 9898

服务端代码:

import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import com.util.JsonUtil;
import com.vo.HtMetaClusterInfoVo;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import java.util.List;/*** @author 何永豪* @className HtMetaSyncService* @description TODO* @date 2023/11/6 15:25*/
@Slf4j
@GrpcService
public class HtMetaSyncService extends HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceImplBase {@Overridepublic void syncMeta(HtMetaSyncRequest request, StreamObserver<HtMetaSyncResponse> responseObserver) {String syncJson = request.getSyncJson();log.info("接收到json:{}",syncJson);List<HtMetaClusterInfoVo> list = JsonUtil.toList(syncJson, HtMetaClusterInfoVo.class);SyncType syncType = request.getSyncType();int number = syncType.getNumber();log.info("同步类型:{}",number);HtMetaSyncResponse syncResponse = HtMetaSyncResponse.newBuilder().setCode("1000").setMsg("同步成功").build();responseObserver.onNext(syncResponse);responseObserver.onCompleted();}}
客户端:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-client</artifactId><packaging>jar</packaging><name>grpc-client</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency></dependencies></project>

yml

server:port: 8088spring:application:name: local-clientgrpc:client:# gRPC配置的名字,GrpcClient注解会用到local-grpc-server:# gRPC服务端地址address: 'static://127.0.0.1:9898'enableKeepAlive: truekeepAliveWithoutCalls: true#认证类型,无加密negotiationType: plaintext

客户端stub

import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import io.grpc.StatusRuntimeException;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;/*** @author xiaoshu*/
@Service
public class HtMetaInfoSyncClient {@GrpcClient("local-grpc-server")private HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceBlockingStub stub;public String syncMeta(final String json,final SyncType syncType) {try {HtMetaSyncResponse htMetaSyncResponse = stub.syncMeta((HtMetaSyncRequest.newBuilder().setSyncJson(json).setSyncType(syncType).build()));String code = htMetaSyncResponse.getCode();String msg = htMetaSyncResponse.getMsg();return code+":"+msg;} catch (final StatusRuntimeException e) {return "FAILED with " + e.getStatus().getCode().name();}}}
实际调用:
@Autowired
private HtMetaInfoSyncClient htMetaInfoSyncClient;@RequestMapping("/htMetaSync")
public String htMetaSync() {String json="";return htMetaInfoSyncClient.syncMeta(json, SyncType.ADD);
}

原生集成

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xiaoshuzxc</groupId><artifactId>grpc-native-api</artifactId><packaging>jar</packaging><name>grpc-native-api</name><description>grpc原生api整合方式</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><grpc.version>1.29.0</grpc.version><proto.version>3.12.0</proto.version><netty.tcnative.version>2.0.30.Final</netty.tcnative.version></properties><dependencyManagement><dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-bom</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-tcnative-boringssl-static</artifactId><version>${netty.tcnative.version}</version><scope>runtime</scope></dependency></dependencies>
</project>
import org.springframework.stereotype.Service;
import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface GrpcService {}

启动grpc服务监听:

import com.annotation.GrpcService;
import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyServerBuilder;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContextBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.stream.Stream;/*** @author 何永豪* @className GrpcServer* @description TODO* @date 2023/11/7 15:56*/
@Slf4j
public class GrpcServer implements CommandLineRunner, DisposableBean {private Server server;@Resourceprivate AbstractApplicationContext applicationContext;@Resourceprivate GrpcProperties grpcProperties;@Overridepublic void destroy() {stop();}@Overridepublic void run(String... args) throws Exception {start();}private SslContextBuilder getSslContextBuilder(){SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(new File(grpcProperties.getServerCertPath()), new File(grpcProperties.getServerPrivateKeyPath()));sslContextBuilder.trustManager(new File(grpcProperties.getServerTrustCertPath()));sslContextBuilder.clientAuth(ClientAuth.REQUIRE);return GrpcSslContexts.configure(sslContextBuilder);}private void start() throws IOException {NettyServerBuilder nettyServerBuilder = NettyServerBuilder.forPort(grpcProperties.getPort());
//                .sslContext(getSslContextBuilder().build()
//                        );scanBeanWithAnnotation(GrpcService.class, BindableService.class).forEach(e->{BindableService bindableService = applicationContext.getBeanFactory().getBean(e, BindableService.class);nettyServerBuilder.addService(bindableService.bindService());});server = nettyServerBuilder.build().start();log.info("grpc start listen {}",grpcProperties.getPort());Thread thread = new Thread(() -> {try {GrpcServer.this.blockUntilShutdown();} catch (InterruptedException e) {log.error("grpc server stopped");throw new RuntimeException(e);}});thread.setDaemon(false);thread.start();}private void stop(){if (server !=null){server.shutdown();}}private void blockUntilShutdown() throws InterruptedException {if (server !=null ){server.awaitTermination();}}private <T> Stream<String> scanBeanWithAnnotation(Class<? extends Annotation> annotionType,Class<T> beanType){String[] beanNamesForType = applicationContext.getBeanNamesForType(beanType);return Stream.of(beanNamesForType).filter(e->{BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(e);Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(annotionType);if (beansWithAnnotation.containsKey(e)){return true;}else if (beanDefinition.getSource() instanceof AnnotatedTypeMetadata){return AnnotatedTypeMetadata.class.cast(beanDefinition.getSource()).isAnnotated(annotionType.getName());}return false;});}}

服务端:

@Slf4j
@GrpcService
public class HtMetaSyncService extends HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceImplBase {@Overridepublic void syncMeta(HtMetaSyncRequest request, StreamObserver<HtMetaSyncResponse> responseObserver) {String syncJson = request.getSyncJson();log.info("接收到json:{}",syncJson);SyncType syncType = request.getSyncType();int number = syncType.getNumber();log.info("同步类型:{}",number);HtMetaSyncResponse syncResponse = HtMetaSyncResponse.newBuilder().setCode("1000").setMsg("同步成功").build();responseObserver.onNext(syncResponse);responseObserver.onCompleted();}}

客户端

import com.config.GrpcProperties;
import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import io.grpc.netty.NettyChannelBuilder;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;/*** @author xiaoshu*/
@Component
public class HtMetaInfoSyncClient {@Resourceprivate GrpcProperties grpcProperties;@SneakyThrowspublic String syncMeta(final String json,final SyncType syncType) {ManagedChannel channel = null;try {channel=NettyChannelBuilder.forAddress(grpcProperties.getServerIp(),grpcProperties.getPort())//非加密连接.usePlaintext()//加密//.sslContext(grpcProperties.buildClentSslContext()).build();HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceBlockingStub stub = HtMetaInfoSyncServiceGrpc.newBlockingStub(channel);HtMetaSyncResponse htMetaSyncResponse = stub.syncMeta((HtMetaSyncRequest.newBuilder().setSyncJson(json).setSyncType(syncType).build()));String code = htMetaSyncResponse.getCode();String msg = htMetaSyncResponse.getMsg();return code+":"+msg;} catch (final StatusRuntimeException e) {return "FAILED with " + e.getStatus().getCode().name();}finally {if (Objects.nonNull(channel)){channel.shutdown();}}}
}
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author 何永豪* @className GrpcConfig* @description TODO* @date 2023/11/7 16:58*/
@Configuration
public class GrpcConfig {@Bean@ConditionalOnProperty(value = "grpc.enable",havingValue = "true",matchIfMissing = true)public GrpcServer grpcServer(){return new GrpcServer();}}
@Component
@ConfigurationProperties(prefix = "grpc")
@Data
public class GrpcProperties {private Integer port;private String  serverIp;private String serverCertPath;private String serverPrivateKeyPath;private String serverTrustCertPath;private String clientCertPath;private String clientCertChainPath;private String clientPrivateKeyPath;/*public SslContext buildClentSslContext() throws SSLException {SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient();sslContextBuilder.trustManager(new File(clientCertPath));sslContextBuilder.keyManager(new File(clientCertChainPath),new File(clientPrivateKeyPath));return sslContextBuilder.build();}*/}
server:port: 8077spring:application:name: grpc-apigrpc:#监听端口port: 6100#目标IPserver-ip: 127.0.0.1#ssl配置server-cert-path: /ca/server/server.crtserver-private-key-path: /ca/server/server.pemserver-trust-cert-path: /ca/server/ca.crt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/137717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SDN和NFV笔记

目录 SDN SDN的引入 SDN的概念 SDN网络部署的方式 SDN架构 OpenFlow SDN与传统网络的区别 SDN的应用 SDN的优点 NFV NFV的概念&#xff1a; NFV的架构&#xff1a; NFV相比于传统物理网元&#xff1a; NFV与SDN的关系 NFV与SDN的相似点 NFV与SDN的不同 SDN SD…

CVE-2023-25194 Kafka JNDI 注入分析

Apache Kafka Clients Jndi Injection 漏洞描述 Apache Kafka 是一个分布式数据流处理平台&#xff0c;可以实时发布、订阅、存储和处理数据流。Kafka Connect 是一种用于在 kafka 和其他系统之间可扩展、可靠的流式传输数据的工具。攻击者可以利用基于 SASL JAAS 配置和 SASL …

计算机毕业设计 基于Web的视频及游戏管理平台的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

OSG交互:选中场景模型并高亮显示

1、目的 可以在osg视图中选中指定模型实体,并高亮显示。共分为两种,一种鼠标点选,一种框选。 2、鼠标点选 2.1 功能说明 生成两组对象,一组cow对象可以被选中,另一组robot不能被选中;点击cow对象被选中高亮,点击robot被选中不高亮;点击空白处,弹出“select nothing!…

【Git】Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c;…

Java,多线程,线程的两种创建方式

首先是多线程的一些相关概念&#xff1a; 相关概念&#xff1a; 程序&#xff08;program&#xff09;&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段静态&#xff08;指不在执行中&#xff09;的代码。 进程&#xff08;process&#xf…

中国电信终端产业联盟5G Inside行业子联盟正式成立!宏电股份作为副理事单位受邀加入

11月9日&#xff0c;中国电信于广州召开“2023中国电信终端生态合作暨中国电信终端产业联盟&#xff08;以下简称CTTA&#xff09;第十四次会员大会”&#xff0c;联盟成员齐聚现场。作为CTTA大会的一个重要环节&#xff0c;中国电信终端产业联盟5G Inside行业子联盟正式成立&a…

[PyTorch][chapter 61][强化学习-免模型学习 off-policy]

前言&#xff1a; 蒙特卡罗的学习基本流程&#xff1a; Policy Evaluation : 生成动作-状态轨迹,完成价值函数的估计。 Policy Improvement: 通过价值函数估计来优化policy。 同策略&#xff08;one-policy&#xff09;&#xff1a;产生 采样轨迹的策略 和要改…

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23 2023年10月13日&#xff0c;美国材料与试验协会&#xff08;ASTM&#xff09;发布了新版玩具安全标准ASTM F963-23 ​根据CPSIA的规定&#xff0c;当ASTM将ASTM F963的拟定修订意见通知CPSC时&#xff0c;若CPSC认为…

实战leetcode(二)

Practice makes perfect&#xff01; 实战一&#xff1a; 这里我们运用快慢指针的思想&#xff0c;我们的slow和fast都指向第一个节点&#xff0c;我们的快指针一次走两步&#xff0c;慢指针一次走一步&#xff0c;当我们的fast指针走到尾的时候&#xff0c;我们的慢指针正好…

使用Nginx和Spring Gateway为SkyWalking的增加登录认证功能

文章目录 1、使用Nginx增加认证。2、使用Spring Gateway增加认证 SkyWalking的可视化后台是没有用户认证功能的&#xff0c;默认下所有知道地址的用户都能访问&#xff0c;官网是建议通过网关增加认证。 本文介绍通过Nginx和Spring Gateway两种方式 1、使用Nginx增加认证。 生…

切换数据库的临时表空间为temp1 / 切换数据库的undo表空间为 undotbs01

目录 ​编辑 一、切换临时表空间 1、登录数据库 2、查询默认临时表空间 3、创建临时表空间temp1&#xff08;我们的目标表空间&#xff09; 4、修改默认temp表空间 5、查询用户默认临时表空间 6、命令总结&#xff1a; 二、切换数据库的undo表空间 1、查询默认undo表…

Wix使用velo添加Google ads tag并在form表单提交时向谷歌发送事件

往head里加代码时&#xff0c;不能看谷歌的代码&#xff0c;要看wix的代码&#xff0c;不然必定踩坑 https://support.wix.com/en/article/tracking-google-ads-conversions-using-wix-custom-code 这里的代码才对&#xff0c;因为wix搞了个velo&#xff0c;这个velo很傻x&am…

RK3399平台开发系列讲解(内存篇)free 命令查看内存占用情况介绍

🚀返回专栏总目录 文章目录 一、free的使用二、free的内容📢free 指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段,以及系统核心使用的缓冲区等。 一、free的使用 -b  以 Byte 为单位显示内存使用情况。-k  以 KB 为单位显示内存使用情况。…

ARM 基础学习记录 / ARM 裸机编程

汇编程序调用 C 程序详情 在 C 程序和 ARM 汇编程序之间相互调用时必须遵守 ATPCS 规则&#xff0c;其是基于 ARM 指令集和 THUMB 指令集过程调用的规范&#xff0c;规定了调用函数如何传递参数&#xff0c;被调用函数如何获取参数&#xff0c;以何种方式传递函数返回值。 寄存…

ARM 基础学习记录 / 异常与GIC介绍

GIC概念 念课本&#xff08;以下内容都是针对"通用中断控制器&#xff08;GIC&#xff09;"而言&#xff0c;直接摘录的&#xff0c;有的地方可能不符人类的理解方式&#xff09;&#xff1a; 通用中断控制器&#xff08;GIC&#xff09;架构提供了严格的规范&…

GPT-4.0网页平台-ChatYY

ChatYY的优势&#xff1a; 1. 支持大部分AI模型&#xff0c;且支持AI绘画&#xff1a; 2. 问答响应速度极快&#xff1a; 3. 代码解析&#xff1a; 4. 支持文档解读&#xff1a; 5. PC、移动端均支持&#xff1a; 访问直达&#xff1a;ChatYY.com

gird 卡片布局

场景一&#xff1a;单元格大小相等 这承载了所有 CSS Grid 中最著名的片段&#xff0c;也是有史以来最伟大的 CSS 技巧之一&#xff1a; 等宽网格响应式卡片实现 .section-content {display: grid;grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));gap: 10px; …

Jmeter+ant+jenkins接口自动化测试

平台简介 一个完整的接口自动化测试平台需要支持接口的自动执行&#xff0c;自动生成测试报告&#xff0c;以及持续集成。Jmeter 支持接口的测试&#xff0c;Ant 支持自动构建&#xff0c;而 Jenkins 支持持续集成&#xff0c;所以三者组合在一起可以构成一个功能完善的接口自动…

LeetCode(6)轮转数组【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 189. 轮转数组 1.题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1…