前面已经讲述了在vertx中,如何实现服务的注册和使用,这里主要讲解接口的暴露层,在vertx中如何实现类似Spring MVC的Controller层。项目源码引用《Vert.x 4 服务代理(Service Proxy)》进行修改
之前把代理服务注册放到MainVerticle里面,这里吧它独立出来,创建了一个ServiceRegistryVerticle
代码示例:
@Slf4j
public class ServiceRegistryVerticle extends AbstractVerticle {
/**
* 扫描的service包
*/
private final String servicePackages;
public ServiceRegistryVerticle(String servicePackages) {
Objects.requireNonNull(servicePackages, "servicePackages is null");
this.servicePackages = servicePackages;
}
@SuppressWarnings("unchecked")
@Override
public void start(Promise<Void> startPromise) throws Exception {
Set<Class<? extends AbstractAsyncService>> services =
ReflectionUtils.getReflections(servicePackages).getSubTypesOf(AbstractAsyncService.class);
ServiceBinder serviceBinder = new ServiceBinder(VertxHolder.getVertx());
if (!services.isEmpty()) {
try {
for (Class<? extends AbstractAsyncService> service : services) {
AbstractAsyncService serviceInstance = service.getDeclaredConstructor().newInstance();
//AbstractAsyncService#registerAddress获取注册地址/ID
//取巧:注册地址=接口全名
String registerAddress = (String) service.getMethod("registerAddress").invoke(serviceInstance);
//AbstractAsyncService#registerInterface获取注册类
Class registerInterfaceClass = (Class) service.getMethod("registerInterface").invoke(serviceInstance);
//注册
serviceBinder
.setAddress(registerAddress)
.register(registerInterfaceClass, serviceInstance);
}
} catch (Exception e) {
log.error("registerServices error : {}", e.getMessage());
}
}
log.info("All async services are registered successfully");
startPromise.complete();
}
}
代码内容和之前《Vert.x 4 服务代理(Service Proxy)》里面的基本一样,就是独立了一个Verticle出来,参数为扫描的service包路径。
用于标记哪些类是用于路由处理的。类似spring的@Controller
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterHandler {
/**
* api 前缀地址
* @return 前缀地址
*/
String value() default "";
/**
* 注册顺序,数字越小越先注册
*/
int order() default 0;
}
用于标记哪些方法具体处理什么路由路径,类似spring的@RequestMapping
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RouterMapping {
/**
* 路由地址
* @return 路由地址
*/
String value();
/**
* 请求方法类型
* @return 方法
*/
RouterMethod method() default RouterMethod.GET;
/**
* 是否覆盖
* @return 是否覆盖
*/
boolean overwrite() default true;
/**
* 接口描述
* @return 接口描述信息
*/
String desc() default "";
/**
* 注册顺序,数字越小越靠前
* @return 注册顺序号
*/
int order() default 0;
/**
* mineType 类型(HTTP - Content-Type)字符串,如:application/json;utf-8
* @return mineType
*/
String consumes() default "";
String produces() default "";
}
方法枚举
public enum RouterMethod {
GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, CONNECT, PATCH,ROUTE
}
用于反射注册所有路由handler
用户接口,对外暴露接口的类,类似Spring的Controller类
@RouterHandler(value = "/api/user")
public class UserApi {
//获取动态代理的service
private UserService userService=AsyncServiceUtils.getAsyncServiceInstance(UserService.class);
@RouterMapping(value = "/getUserById/:id")
public Handler<RoutingContext> findById() {
return ctx ->{
String id = ctx.pathParam("id");
userService.getUserById(Integer.parseInt(id),handler->{
if(handler.succeeded()){
JsonObject result = handler.result();
ctx.json(result);
}else {
ctx.fail(handler.cause());
}
});
};
}
}
用于注册路由到vertx和创建http server
/**
* 注意必须先注册服务类再注册本类
* 路由构建发布以及HTTP服务启动
*/
@Slf4j
public class RouterRegistryVerticle extends AbstractVerticle {
/**
* 路由handler类包名
*/
String routerPackages;
HttpServer server;
public RouterRegistryVerticle(String routerPackages) {
this.routerPackages = routerPackages;
}
@Override
public void start(Promise<Void> startPromise) throws Exception {
String contextPath = config().getString("contextPath", "/");
Integer port = config().getInteger("port", 8080);
Router router = new RouterHandlerFactory(routerPackages,contextPath).createRouter();
HttpServerOptions options=new HttpServerOptions();
options.setPort(port);
server = vertx.createHttpServer(options).requestHandler(router).listen(ar -> {
if (ar.succeeded()) {
log.info("All router handler are registered successfully and http server listening on port {}", ar.result().actualPort());
startPromise.complete();
} else {
startPromise.fail(ar.cause());
}
});
}
@Override
public void stop(Promise<Void> stopPromise) throws Exception {
if (Objects.isNull(server)) {
stopPromise.complete();
}
server.close(voidAsyncResult -> {
if (voidAsyncResult.succeeded()) {
stopPromise.complete();
}else{
stopPromise.fail(voidAsyncResult.cause());
}
});
}
}
核心启动类
@Slf4j
public class MainVerticle extends AbstractVerticle {
@Override
public void start(Promise<Void> startPromise) throws Exception {
//初始化
VertxHolder.init(vertx);
//注册服务
vertx.deployVerticle(new ServiceRegistryVerticle(config().getString("servicePackages","com.demo.vertx.vertx_demo.service"))).onSuccess(handler -> {
vertx.deployVerticle(new RouterRegistryVerticle(config().getString("routerPackages","com.demo.vertx.vertx_demo")));
});
}
}
提示:注意verticle之间的部署启动顺序
使用MainVerticle启动项目
io.vertx.core.Launcher run com.demo.vertx.vertx_demo.MainVerticle
观察控制台
可以看到输出日志内容与我们预期结果一致,接下来使用postman工具访问接口测试
观察测试返回,与预期结果一致。
组合前面所学至此可以完整的开发项目了。
https://www.leftso.com/article/2408151241429547.html