Spring调用vertx异步service Interface

article/2025/8/21 3:54:16

Spring调用Vertx异步service Interface

    • 情景
    • 原理
    • 实现
      • 工程结构说明
      • 目录结构
      • 样例代码
        • example-vertx-interface
          • pom依赖
          • 代码
        • example-vertx-cluster
          • pom依赖
          • 代码
        • lm-spring-vertx-ebclient
          • pom依赖
          • 代码
            • @VertxEBClientScan
            • VertxEBClientScannerRegister
            • VertxEBProxyBeanDefinitionRegistryPostProcessor
            • VertxServiceScanner
            • VertxEBProxyFactoryBean
            • AwaitUtil
        • example-spring-vertx-ebclient
          • pom依赖
          • 代码
        • 样例代码效果展示
      • 制作spring-boot-starter
        • lm-spring-vertx-ebclient-starter
        • lm-spring-vertx-autoconfigure

情景

现有基于Vertx开发的中台应用,新立项一个基于Spring开发的活动应用,需要调用中台应用提供的各种服务能力。

现存问题:

  • 中台应用对外提供服务能力,对于非Vertx项目,仅有HTTP RESTful SDK
  • SDK有HTTP网协议络消耗
  • 新加接口需要SDK的开发工作

期待:

  • 比HTTP协议更高效的网络通讯
  • 减少新加接口的开发工作
  • 简化上游应用对下游服务接入的开发工作

原理

基于Vertx部署的Vertical实例之间的通讯由vertx-eventbus完成,vertx service之间的调用,靠的就是eventbus,同Vertical实例service之间使用的是本地eventbus,没有网络开销,而不同Vertical实例service之间的使用的集群eventbus,底层会使用TCP/IP的方式连接。

Vertx提供services-proxy机制来简化eventbus的冗余样板代码,底层是通过代码生成技术,为service interface生成代理类,完成服务注册,服务远程调用的eventbus代码实现。

Spring提供了FactoryBean机制,可以为service interface生成代理bean实例。因此我们可以s类似于spring+dubbospring+vertx的高效RPC。

实现

工程结构说明

一共会启动3个应用:

  • HelloInstance(提供HelloService服务)
  • NameInstance(提供NameService服务)
  • Application(Spring构建的应用,需要调用到HelloService、NameService服务)

目录结构

共7个maven module:

  • example-vertx-interface(接口样例)
  • example-vertx-cluster(vertx集群样例)
  • example-spring-vertx-ebclient(spring+vertx整合样例)
  • example-spring-vertx-ebclient-starter(spring-boot+vertx整合样例)
  • lm-spring-vertx-ebclient(spring+)
  • lm-spring-vertx-autoconfigure
  • lm-spring-vertx-ebclient-starter

3个example,1个spring整合

├─example
│  ├─example-lm-spring-vertx-ebclient
│  │  ├─example-spring-vertx-ebclient
│  │  │  └─src
│  │  │      └─main
│  │  │          ├─java
│  │  │          │  └─com
│  │  │          │      └─luomin
│  │  │          │          └─example
│  │  │          │              │  Application.java
│  │  │          │              ├─config
│  │  │          │              │      VertxEBClientConfig.java
│  │  │          │              └─controller
│  │  │          │                      HelloController.java
│  │  │          └─resources
│  │  │                  cluster.xml
│  │  │
│  │  ├─example-spring-vertx-ebclient-starter
│  │  │  ├─src
│  │  │  │  └─main
│  │  │  │      ├─java
│  │  │  │      │  └─com
│  │  │  │      │      └─luomin
│  │  │  │      │          └─example
│  │  │  │      │              │  Application.java
│  │  │  │      │              └─controller
│  │  │  │      │                      HelloController.java
│  │  │  │      └─resources
│  │  │  │              cluster.xml
│  │  │
│  │  ├─example-vertx-cluster
│  │  │  │  example-vertx-cluster.iml
│  │  │  │  pom.xml
│  │  │  │
│  │  │  └─src
│  │  │      └─main
│  │  │          ├─java
│  │  │          │  └─com
│  │  │          │      └─luomin
│  │  │          │          └─example
│  │  │          │              │  HelloInstance.java
│  │  │          │              │  NameInstance.java
│  │  │          │              ├─service
│  │  │          │              │  └─impl
│  │  │          │              │          HelloServiceImpl.java
│  │  │          │              │          NameServiceImpl.java
│  │  │          │              └─verticle
│  │  │          │                      HelloApi.java
│  │  │          │
│  │  │          └─resources
│  │  │                  cluster.xml
│  │  │
│  │  └─example-vertx-interface
│  │      │  example-vertx-interface.iml
│  │      │  pom.xml
│  │      │
│  │      ├─src
│  │      │  └─main
│  │      │      └─java
│  │      │          └─com
│  │      │              └─luomin
│  │      │                  └─example
│  │      │                      └─service
│  │      │                              HelloService.java
│  │      │                              NameService.java
│  │      │                              package-info.java
│  │
├─lm-spring-vertx-autoconfigure
│  ├─src
│  │  └─main
│  │      ├─java
│  │      │  └─com
│  │      │      └─luomin
│  │      │          └─autoconfig
│  │      │              └─ebclient
│  │      │                      AutoConfiguredVertxEBClientScannerRegister.java
│  │      │                      EbClientAutoConfiguration.java
│  │      │
│  │      └─resources
│  │          └─META-INF
│  │                  spring.factories
│  │
├─lm-spring-vertx-ebclient
│  ├─src
│  │  └─main
│  │      └─java
│  │          └─com
│  │              └─luomin
│  │                  └─ebclient
│  │                      ├─annotation
│  │                      │      VertxEBClientScan.java
│  │                      │      VertxEBClientScannerRegister.java
│  │                      │
│  │                      ├─factorybean
│  │                      │      VertxEBProxyFactoryBean.java
│  │                      ├─postprocessor
│  │                      │      VertxEBProxyBeanDefinitionRegistryPostProcessor.java
│  │                      ├─scanner
│  │                      │      VertxServiceScanner.java
│  │                      └─util
│  │                              AwaitUtil.java
│  │
├─lm-spring-vertx-ebclient-starter
│      pom.xml

样例代码

example-vertx-interface

example-vertx-interface是vertx下游服务的接口,并且也会生成代理实现类,待会也会被spring所依赖。

pom依赖
<dependencies><dependency><groupId>io.vertx</groupId><artifactId>vertx-service-proxy</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-codegen</artifactId><version>3.9.14</version><classifier>processor</classifier></dependency></dependencies><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessors><annotationProcessor>io.vertx.codegen.CodeGenProcessor</annotationProcessor></annotationProcessors></configuration></plugin></plugins></build>
代码
@ModuleGen(name = "example", groupPackage = "com.luomin.example.service")
package com.luomin.example.service;
import io.vertx.codegen.annotations.ModuleGen;
@ProxyGen
public interface HelloService {void sayHello(String name, Handler<AsyncResult<String>> resultHandler);
}
@ProxyGen
public interface NameService {void getName(Handler<AsyncResult<String>> resultHandler);
}

example-vertx-cluster

example-vertx-cluster会启动两个vertx实例,分别部署vertical,用于提供服务。

pom依赖
<dependencies><dependency><groupId>io.vertx</groupId><artifactId>vertx-web</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-hazelcast</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-service-proxy</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-codegen</artifactId><version>3.9.14</version><classifier>processor</classifier></dependency><dependency><groupId>com.luomin</groupId><artifactId>example-vertx-interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessors><annotationProcessor>io.vertx.codegen.CodeGenProcessor</annotationProcessor></annotationProcessors></configuration></plugin></plugins></build>
代码
public class NameServiceImpl implements NameService {private final List<String> nameList = new ArrayList<>();private int index = 0;public NameServiceImpl() {nameList.add("luomin");nameList.add("xym");nameList.add("hehe");}@Overridepublic void getName(Handler<AsyncResult<String>> resultHandler) {resultHandler.handle(Future.succeededFuture(getName()));}private String getName() {if (index >= nameList.size()) {index = 0;}System.out.println("index = " + index);String name = nameList.get(index);index++;return name;}
}
public class HelloServiceImpl implements HelloService {@Overridepublic void sayHello(String name, Handler<AsyncResult<String>> resultHandler) {resultHandler.handle(Future.succeededFuture("hello " + name));}
}
public class HelloApi extends AbstractVerticle {private HelloService helloService;private NameService nameService;@Overridepublic void start() throws Exception {this.initService();HttpServer httpServer = vertx.createHttpServer();Router router = Router.router(vertx);router.route("/index").handler(routingContext -> {HttpServerResponse response = routingContext.response();response.putHeader("content-type", "text/plain");Future.<String>future(promise -> this.nameService.getName(promise)).compose(name -> Future.<String>future(promise -> this.helloService.sayHello(name, promise))).onSuccess(response::end).onFailure(t -> response.end(t.getMessage()));});httpServer.requestHandler(router);httpServer.listen(10000);}private void initService() {this.helloService = new ServiceProxyBuilder(vertx).setAddress(HelloService.class.getName()).build(HelloService.class);this.nameService = new ServiceProxyBuilder(vertx).setAddress(NameService.class.getName()).build(NameService.class);}
}
public class HelloInstance {public static void main(String[] args) {ClusterManager mgr = new HazelcastClusterManager();VertxOptions options = new VertxOptions().setClusterManager(mgr);Vertx.clusteredVertx(options, res -> {if (res.succeeded()) {System.out.println("cluster启动成功");Vertx vertx = res.result();vertx.deployVerticle(HelloApi.class.getName(), res1 -> {if (res1.succeeded()) {System.out.println("部署HelloApi成功");new ServiceBinder(vertx).setAddress(HelloService.class.getName()).register(HelloService.class, new HelloServiceImpl());System.out.println("注册HelloService成功");}});}});}
}
public class NameInstance {public static void main(String[] args) {ClusterManager mgr = new HazelcastClusterManager();VertxOptions options = new VertxOptions().setClusterManager(mgr);Vertx.clusteredVertx(options, res -> {if (res.succeeded()) {System.out.println("cluster启动成功");Vertx vertx = res.result();new ServiceBinder(vertx).setAddress(NameService.class.getName()).register(NameService.class, new NameServiceImpl());System.out.println("注册NameService成功");}});}
}

lm-spring-vertx-ebclient

lm-spring-vertx-ebclient用于spring整合vertx service proxy机制,能够通过java interface注入bean。

pom依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.14</version><scope>provided</scope></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-core</artifactId><version>3.9.14</version><scope>provided</scope></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-codegen</artifactId><version>3.9.14</version><scope>provided</scope></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-service-proxy</artifactId><version>3.9.14</version><scope>provided</scope></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-hazelcast</artifactId><version>3.9.14</version><scope>provided</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>provided</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version><scope>provided</scope></dependency></dependencies>
代码
@VertxEBClientScan

用于扫描需要生成代理的Service接口的注解。
这里用@Import导入我们的组件。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(VertxEBClientScannerRegister.class)
public @interface VertxEBClientScan {String[] value() default {};
}
VertxEBClientScannerRegister

VertxEBClientScannerRegister获取@VertxEBClientScan指定扫描的包路径。
注册并配置VertxEBProxyBeanDefinitionRegistryPostProcessor

@Slf4j
public class VertxEBClientScannerRegister implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {AnnotationAttributes ebClientScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(VertxEBClientScan.class.getName()));if (ebClientScanAttrs != null) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(VertxEBProxyBeanDefinitionRegistryPostProcessor.class);builder.addPropertyReference("vertx", "vertx");List<String> basePackages = Arrays.stream(ebClientScanAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList());builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);registry.registerBeanDefinition(beanName, beanDefinition);} else  {log.warn("not found VertxEBClientScan annotation");}}
}
VertxEBProxyBeanDefinitionRegistryPostProcessor

VertxEBProxyBeanDefinitionRegistryPostProcessor 创建VertxServiceScanner用于实际的扫描。

public class VertxEBProxyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Setterprivate Vertx vertx;@Setterprivate String basePackage;@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {VertxServiceScanner scanner = new VertxServiceScanner(registry, vertx);scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}}
VertxServiceScanner

VertxServiceScanner 扫描类路径下指定包路径的被ProxyGen修饰的Service接口,得到Set<BeanDefinitionHolder>,对这些BeanDefinitionHolder进行修改配置,指定class=VertxEBProxyFactoryBean

public class VertxServiceScanner extends ClassPathBeanDefinitionScanner {private final Vertx vertx;public VertxServiceScanner(BeanDefinitionRegistry registry, Vertx vertx) {super(registry, false);this.vertx = vertx;this.addIncludeFilter(new AnnotationTypeFilter(ProxyGen.class));}@Overrideprotected Set<BeanDefinitionHolder> doScan(String... basePackages) {logger.info("scan basePackages=" + Arrays.toString(basePackages));Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);if (beanDefinitionHolders.isEmpty()) {logger.warn("not found any BeanDefinition");} else {processBeanDefinition(beanDefinitionHolders);}return beanDefinitionHolders;}@Overrideprotected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {AnnotationMetadata metadata = beanDefinition.getMetadata();return metadata.isInterface();}private void processBeanDefinition(Set<BeanDefinitionHolder> beanDefinitionHolders) {beanDefinitionHolders.forEach(bd -> {BeanDefinition beanDefinition = bd.getBeanDefinition();String beanClassName = beanDefinition.getBeanClassName();Class<?> beanClass;try {beanClass = Class.forName(beanClassName);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}beanDefinition.setBeanClassName(VertxEBProxyFactoryBean.class.getName());MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();propertyValues.add("serviceProxyBuilder", new ServiceProxyBuilder(this.vertx).setAddress(beanClassName));propertyValues.add("serviceClass", beanClass);});}}
VertxEBProxyFactoryBean

VertxEBProxyFactoryBean 用于返回bean实例,这里使用ServiceProxyBuilder生成代理对象。

@Slf4j
public class VertxEBProxyFactoryBean implements FactoryBean<Object> {@Getter@Setterprivate ServiceProxyBuilder serviceProxyBuilder;@Getter@Setterprivate Class<?> serviceClass;@Overridepublic Object getObject() throws Exception {log.info("build service proxy, serviceClass={}", serviceClass.getName());return serviceProxyBuilder.build(serviceClass);}@Overridepublic Class<?> getObjectType() {return serviceClass;}}
AwaitUtil

用于Spring环境中同步调用Service异步方法的工具类。

public class AwaitUtil {public static <T> T awaitResult(Consumer<Handler<AsyncResult<T>>> runnable) throws ExecutionException, InterruptedException {// TODO: 2022/12/5 如果是在vertx的io线程调用future.get()会导致io线程陷入死阻塞checkVertxEventLoop();CompletableFuture<T> future = toCompletableFuture(runnable);return future.get();}public static <T> CompletableFuture<T> toCompletableFuture(Consumer<Handler<AsyncResult<T>>> runnable) {checkVertxEventLoop();CompletableFuture<T> future = new CompletableFuture<>();Handler<AsyncResult<T>> resultHandler = newHandler(future);runnable.accept(resultHandler);return future;}private static <T> Handler<AsyncResult<T>> newHandler(CompletableFuture<T> future) {return event -> {if (event.succeeded()) {future.complete(event.result());} else future.completeExceptionally(event.cause());};}private static void checkVertxEventLoop() {if (isInVertxEventLoop()) throw new RuntimeException("not support blocking call in vertx eventLoop");}private static boolean isInVertxEventLoop() {return Thread.currentThread() instanceof VertxThread && ((VertxThread) Thread.currentThread()).isWorker();}
}

example-spring-vertx-ebclient

pom依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.6.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.2</version></dependency><dependency><groupId>com.luomin</groupId><artifactId>example-vertx-interface</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.luomin</groupId><artifactId>lm-spring-vertx-ebclient</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-core</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-codegen</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-service-proxy</artifactId><version>3.9.14</version></dependency><dependency><groupId>io.vertx</groupId><artifactId>vertx-hazelcast</artifactId><version>3.9.14</version></dependency></dependencies>
代码

代码很简单,一个SpringBoot ,一个测试用的Controller,一个配置类。

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
@Configuration
@VertxEBClientScan("com.luomin.example")
public class VertxEBClientConfig {@Beanpublic Vertx vertx() throws ExecutionException, InterruptedException {ClusterManager mgr = new HazelcastClusterManager();VertxOptions options = new VertxOptions().setClusterManager(mgr);return AwaitUtil.awaitResult(resultHandler -> Vertx.clusteredVertx(options, resultHandler));}
}
@RestController
public class HelloController {@Autowiredprivate HelloService helloService;@Autowiredprivate NameService nameService;@GetMapping("/index")public String index() throws ExecutionException, InterruptedException {String name = AwaitUtil.awaitResult(resultHandler -> this.nameService.getName(resultHandler));String msg = AwaitUtil.awaitResult(resultHandler -> this.helloService.sayHello(name, resultHandler));return msg;}
}

样例代码效果展示

启动HelloInstance、NameInstance、Application后,可以看到当前Vertx集群共有3个节点。
在这里插入图片描述
观察日志,看到扫描的包路径跟路径下的Service接口。
在这里插入图片描述
访问 http://localhost:8080/index,可以看到已经注入了bean实例为Vertx的xxxxVertxEBProxy
在这里插入图片描述

制作spring-boot-starter

制作spring-boot-starter,使用的时候只需要引入依赖即可,目前功能简单,也就不需要什么配置文件了。

lm-spring-vertx-ebclient-starter

这里只做依赖管理,现在还没对版本进来管理。

<dependencies><dependency><groupId>com.luomin</groupId><artifactId>lm-spring-vertx-autoconfigure</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.luomin</groupId><artifactId>lm-spring-vertx-ebclient</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></dependency></dependencies>

lm-spring-vertx-autoconfigure

META-INF\spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.luomin.autoconfig.ebclient.EbClientAutoConfiguration

自动配置类

@Import(AutoConfiguredVertxEBClientScannerRegister.class)
@ConditionalOnClass(Vertx.class)
public class EbClientAutoConfiguration {@Bean@ConditionalOnMissingBean(Vertx.class)public Vertx vertx() throws Exception {ClusterManager mgr = new HazelcastClusterManager();VertxOptions options = new VertxOptions().setClusterManager(mgr);return AwaitUtil.awaitResult(resultHandler -> Vertx.clusteredVertx(options, resultHandler));}}

自动路径扫描配置类

public class AutoConfiguredVertxEBClientScannerRegister implements BeanFactoryAware, ImportBeanDefinitionRegistrar {private BeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(VertxEBProxyBeanDefinitionRegistryPostProcessor.class);builder.addPropertyReference("vertx", "vertx");List<String> basePackages = AutoConfigurationPackages.get(this.beanFactory);builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);registry.registerBeanDefinition(beanName, beanDefinition);}}

http://chatgpt.dhexx.cn/article/pjRogA5L.shtml

相关文章

Vert.x - SpringBoot 整合 vertx 使用 thymeleaf、freemarker 模板引擎

一、模板引擎 在 SpringMVC 项目中使用模板引擎&#xff0c;使用较多的应该是 thymeleaf 及 freemarker 了吧&#xff0c;虽然现在前后端分离的浪潮已经席卷而来&#xff0c;但对于 SEO 或者 页面静态话来说&#xff0c;后端的模板引擎还是具有一定的作用力。本篇文章继续上篇…

Vert.x - SpringBoot 整合 vertx

一、vertx 前面的文章讲解了 vertx 的简介及 vertx-web 的路由&#xff0c;看过的小伙伴应该对 vertx 有了一定的了解&#xff0c;从前面的演示来看&#xff0c;都是单独使用的 vertx &#xff0c;对于目前的后端来说 SpringBoot 可是一个非常火热的框架&#xff0c;那如果将 …

Vert.x - vertx-web 路由讲解总结

一、vertx-web 上篇文章我们对 vertx 进行了简单的介绍&#xff0c;并使用 vertx-web 实践了 restFul 接口的书写&#xff0c;本篇文章接着上篇继续讲解 vertx-web 的路由。 下面是上篇文章的地址&#xff1a; https://blog.csdn.net/qq_43692950/article/details/123955368 …

vertx的http服务实现分布式session

vetrx是基于netty封装的java网络编程框架&#xff0c;比netty开发较为简单&#xff0c;在其基础上提供很多有用功能&#xff0c;能在较短的时间内开发一个http服务器&#xff0c;或其他网络服务。今天我们展示下如何为vertx开发http网关实现分布式session,实现参考spring sessi…

Vert.x入门1 —— 《基础概念》

一、什么是Vertx Vert.x 在JVM上构建响应式应用程序的工具包&#xff0c;Vert.x不是框架而是工具包。Vert.x基于Netty项目&#xff0c;该项目是JVM的高性能异步网络库。 此描述中有三个重要点&#xff1a;工具包&#xff0c;响应式和“在JVM上”。 首先&#xff0c;Vert.x是…

Vertx快速入门参考

Vertx学习 什么是vertx&#xff1f; Vert.x最大的特点就在于异步&#xff08;底层基于Netty&#xff09;&#xff0c;通过事件循环&#xff08;EventLoop&#xff09;来调起存储在异步任务队列&#xff08;CallBackQueue&#xff09;中的任务&#xff0c;大大降低了传统阻塞模…

Vertx入门学习(含代码)

Vertx入门学习 一、Vertx是什么&#xff1f;二、Vertx基本概念三、Vertx能干什么&#xff1f;四、Vertx的技术体系五、快速体验&#xff1a;搭建一个简单的Vertx项目并输出Hello World六、单元测试总结 一、Vertx是什么&#xff1f; github: https://github.com/vert-x3 官网&…

Vert.x(vertx) 简明介绍

摘要 Vert.x最大的特点就在于异步&#xff08;底层基于Netty&#xff09;&#xff0c;通过事件循环&#xff08;EventLoop&#xff09;来调起存储在异步任务队列&#xff08;CallBackQueue&#xff09;中的任务&#xff0c;大大降低了传统阻塞模型中线程对于操作系统的开销。因…

Vertx学习一:这玩意是到底是个啥

Vertx&#xff0c;融合Java、Ruby、Python等语言的高性能架构&#xff0c;架构师必读 原文链接&#xff1a; http://www.360doc.com/content/18/0203/14/39530679_727432611.shtml 目录&#xff1a; 一、Vert.x简介 二、Vert.x原理解析 三、Vert牛刀小试 四、Vert应用实践 五…

【java】vertx从入门到放弃——入门(四)Codec

什么是Codec&#xff1f;概念这个玩意我是真不想说&#xff0c;毕竟我没有找到具体的概念&#xff0c;我自己大致的理解就是&#xff0c;用EventBus传输类的时候&#xff0c;对这个类进行序列化和反序列化的东西&#xff0c;因为vertx使用json进行传输&#xff0c;所以这个玩意…

Android thinker

国家虽安&#xff0c;忘战必危&#xff0c; Android虽爽&#xff0c;不学则忙&#xff0c;老夫纵横江湖数十载&#xff0c;深谙世事之难料&#xff0c;顾。。 ok&#xff0c;ok 不装比了&#xff0c;进入正题&#xff0c;今天要讲的是Android 热修之 thinker。 在研究这个之前…

ESP32-CAM AI THINKER 引脚排列:GPIO 用法说明

ESP32-CAM 是一款开发板,带有一个 ESP32-S 芯片、一个 OV2640 摄像头、microSD 卡插槽和几个用于连接外设的 GPIO。在本指南中,我们将介绍 ESP32-CAM GPIO 以及如何使用它们。 引脚排列图 下图显示了 ESP32-CAM AI-Thinker 的引脚排列图。 电路原理示意图 下图显示了 ESP…

Thinkpad 各系列简介

ThinkPad 各系列简介 如果提到商务笔记本&#xff0c;大家一定会想到凭借坚固和可靠的特性在业界享有很高声誉ThinkPad笔记本电脑&#xff0c;以及ThinkPad那经典的键盘红点设计和纯黑低调的外表。 在这里我就简单介绍一下ThinkPad的各系列产品。 Thinkpad名称来历 “ThinkP…

python thinker canvas create_arc 使用详解

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a;https://blog.csdn.net/A757291228/article/details/106739556 ———————————————— 版权声明&#xff1a;本文…

二、让界面动起来,Python基于thinker实现的简单的俄罗斯方块小游戏

文章目录 界面动起来定时刷新页面移动俄罗斯方块 界面动起来 **功能&#xff1a;**如何让方块「动起来」? 分析过程&#xff1a; 要想让方块动起来&#xff0c;需要实现以下两点&#xff1a; 定时刷新页面移动页面内部的俄罗斯方块 定时刷新页面 实现定时刷新页面&#xff…

三、生成随机方块,Python基于thinker实现的简单的俄罗斯方块小游戏

文章目录 生成第一步&#xff1a;随机生成方块对象第二步&#xff1a;修改游戏运行方法 固定第一步&#xff1a;记录固定的方块第二步&#xff1a;修改check_move方法 左右移动第一步&#xff1a;左右移动方块第二步&#xff1a;绑定键盘 旋转第一步&#xff1a;添加旋转方法第…

【G-thinker】G-thinker部分源码解析

一、main 子图匹配程序run.cpp中主要使用到worker.h和comper.h分别对应线程和进程单位&#xff0c;接下来我们从main函数入手解析源码 从主函数可以看到&#xff0c;子图匹配程序中GMatchWorker继承了worker&#xff0c;主函数声明了workerparams并且传入了路径和线程参数&am…

python用thinker库制作一个进制转换器(可打包exe)

进制类型分为&#xff1a; 二进制 字母B表示 八进制 字母O表示 十进制 字母D表示 十六机制 字母H表示 进制转换之间很麻烦&#xff0c;还得计算&#xff0c;如果可以做一个进制转换器多nice&#xff0c;其实也不难&#xff0c;就利用一个tkinter库就能制作&#xff0c;废话不多…

Thinker Board 2开发板上使用奥比中光 astra 深度相机

Thinker Board 2 国产开发板 arm架构 上使用奥比中光 astra 深度相机 准备工作 1、下载astraSDK 选择linux_arm 下载 https://developer.orbbec.com.cn/download.html?id53 2、下载openNI https://dl.orbbec3d.com/dist/openni2/OpenNI_2.3.0.66.zip 开始安装 1、安装fre…

think

我167&#xff0c;97斤&#xff0c;胸d&#xff0c;腰很细&#xff0c;反手轻松摸肚脐那种&#xff0c;骨架小&#xff0c;总结就是身高刚好人瘦胸大屁股大腿细腰细肤白。走路腰杆能挺到天上&#xff0c;气质挺好。漂亮女生太多了&#xff0c;想取胜只能从气质下手了。脸呢&…