KivaKit微服务的详细指南

103 阅读5分钟

KivaKit微服务

KivaKit微服务

KivaKit旨在使微服务的编码更快、更容易。在这篇博文中,我们将研究 kivakit-microservice模块。截至目前,该模块只能通过SNAPSHOT构建和构建KivaKit来提前访问。KivaKit 1.1的最终版本将包括这个模块,并且应该在2021年10月底或更早发生。

它是做什么的?

kivakit-microservice迷你框架使得实现REST-ful GET、POST和DELETE处理程序以及这些处理程序安装在特定路径上变得容易。大多数REST微服务的常规管道都被处理了,包括:

  • Jetty网络服务器的配置和启动
  • 处理GET、POST和DELETE请求
  • 用Json对JSON对象进行序列化
  • 使用KivaKit消息传递进行错误处理
  • 生成一个OpenAPI规范
  • 用Swagger查看OpenAPI规范
  • 启动Apache Wicket网络应用程序

微服务

下面的DivisionMicroservice类是一个微服务,用于执行算术除法(以可以想象的最慢、最昂贵的方式)。微服务的超类提供了Jetty服务器的自动配置和启动:

public class DivisionMicroservice extends Microservice
{
    public static void main(final String[] arguments)
    {
        new DivisionMicroservice().run(arguments);
    }

    @Override
    public MicroserviceMetadata metadata()
    {
        return new MicroserviceMetadata()
                .withName("divide-microservice")
                .withDescription("Example microservice for division")
                .withVersion(Version.parse("1.0"));
    }

    @Override
    public void onInitialize()
    {
        // Register components here 
    } 
        
    public DivideRestApplication restApplication()
    {
        return new DivideRestApplication(this);
    }
}

在这里,main(String[] arguments)方法创建了一个DivisionMicroservice的实例,并通过调用*run(String[] )*来启动它的运行(与任何KivaKit应用程序相同)。*metadata()*方法返回包含在REST OpenAPI规范中的服务信息(安装在/open-api/swagger.json)。*restApplication()*工厂方法为微服务创建一个REST应用程序,*webApplication()工厂方法可以选择创建一个Apache Wicket Web应用程序,用于配置服务和查看其状态。微服务的任何初始化都必须在onInitialize()*方法中进行。这是注册整个应用中使用的组件的最佳位置。

run(String[] arguments)方法被调用时,Jetty Web服务器会在由-deployment开关加载的MicroserviceSettings对象指定的端口上启动。可以使用*-port*命令行开关来覆盖这个值。

当微服务启动时,以下资源是可用的:

资源路径描述
/Apache Wicket网络应用
/KivaKit microservlet REST应用程序
/资产静态资源
/docsSwagger OpenAPI 文档
/open-api/assetsOpenAPI资源(.yaml文件)。
/open-api/swagger.jsonOpenAPI规范
/swagger/webappSwagger网络应用程序
/swagger/webjarSwagger设计资源

REST应用

一个REST应用程序是通过扩展MicroserviceRestApplication类来创建的:

public class DivideRestApplication extends MicroserviceRestApplication
{
	public DivideRestApplication(Microservice microservice)
	{
		super(microservice);
	}
	
	@Override
	public void onInitialize()
	{
		mount("divide", DivideRequest.class);
	}
}

请求处理程序必须被挂载在onInitialize()方法里面的特定路径上(否则会报告错误)。如果挂载路径(在本例中为 "divide")不是以斜线("/")开头,则会自动预加路径"/api/[major-version].[minor-version]/"。因此,在上面的代码中,"divide "变成了"/api/1.0/divide",其中的1.0版本来自DivideMicroservice返回的元数据。同样的路径可以用来为每种HTTP方法(GET、POST、DELETE)装载一个请求处理程序。然而,试图在同一路径上为同一HTTP方法装载两个处理程序将导致错误。

gsonFactory()工厂方法(上面没有显示)可以选择提供一个创建配置的Gson对象的工厂。Gson工厂应该扩展MicroserviceGsonFactory类。KivaKit将在序列化和反序列化JSON对象时使用该工厂。

Microservlets

Microservlets处理 GET、POST 和 DELETE 请求。它们被安装在路径上,与请求处理程序的安装方式相同。但与请求处理程序不同的是,microservlet可以同时处理任何或所有HTTP请求方法。请求处理程序比microservlet更灵活,通常也更有用,所以这里主要是为了完整地介绍这一信息。microservlets的关键用例(到目前为止是唯一的用例)是它们被用来实现请求处理程序。你可以在MicroserviceRestApplication的*mount(String path, Class requestType)*方法中看到用于此目的的内部微服务。

请求处理程序

请求处理程序通过调用mount(String path, Class requestType)被安装到MicroserviceRestApplication上。它们有三种类型,每种类型都是MicroserviceRequest 的子类:

  • MicroservletGetRequest
  • MicroservletPostRequest
  • MicroservletDeleteRequest

下面,我们看到一个POST请求处理程序,DivideRequest,它将两个数字分开。响应是由嵌套的DivideResponse类制定的。使用来自*@OpenApi注解的信息生成一个OpenAPI规范。最后,请求通过实现MicroservletPostRequest要求的Validatable*接口来执行自我验证:

@OpenApiIncludeType(description = "Request for divisive action")
public class DivideRequest extends MicroservletPostRequest
{
    @OpenApiIncludeType(description = "Response to a divide request")
    public class DivideResponse extends MicroservletResponse
    {
        @Expose
        @OpenApiIncludeMember(description = "The result of dividing",
                              example = "42")
        int quotient;

        public DivideResponse()
        {
            this.quotient = dividend / divisor;
        }

        public String toString()
        {
            return Integer.toString(quotient);
        }
    }

    @Expose
    @OpenApiIncludeMember(description = "The number to be divided",
                          example = "84")
    private int dividend;

    @Expose
    @OpenApiIncludeMember(description = "The number to divide the dividend by",
                          example = "2")
    private int divisor;

    public DivideRequest(int dividend, int divisor)
    {
        this.dividend = dividend;
        this.divisor = divisor;
    }

    public DivideRequest()
    {
    }

    @Override
    @OpenApiRequestHandler(summary = "Divides two numbers")
    public DivideResponse onPost()
    {
        return listenTo(new DivideResponse());
    }

    @Override
    public Class<DivideResponse> responseType()
    {
        return DivideResponse.class;
    }

    @Override
    public Validator validator(ValidationType type)
    {
        return new BaseValidator()
        {
            @Override
            protected void onValidate()
            {
                problemIf(divisor == 0, "Cannot divide by zero");
            }
        };
    }
}

注意,嵌套的响应类使用外层类来访问请求的字段。这使得getters和setters没有必要。当KivaKit调用onPost()时,响应对象被创建(由于调用listenTo(),它产生的任何消息都会被重复,DivideResponse对象的构造器会执行分割操作。这使得*onPost()*处理程序成为一个单行程序:

public DivideResponse onPost()
	{
	    return listenTo(new DivideResponse());
	}

请注意OO设计原则是如何改进封装、消除模板和增加可读性的。

在Java中访问KivaKit微服务

kivakit-microservice模块包括MicroserviceClient,它可以在Java中轻松访问KivaKit微服务。该客户端可以像这样使用:

public class DivisionClient extends Application
{
    public static void main(String[] arguments)
    {
        new DivisionClient().run(arguments);
    }

    @Override
    protected void onRun()
    {
        var client = listenTo(new MicroservletClient(
            new MicroserviceGsonFactory(), 
            Host.local().https(8086), 
            Version.parse("1.0"));

        var response = client.post("divide", 
            DivideRequest.DivideResponse.class, 
            new DivideRequest(9, 3));

        Message.println(AsciiArt.box("response => $", response));
    }
}

在这里,我们创建了一个MicroservletClient来访问我们上面构建的微服务。我们告诉它在本地主机的8086端口使用该服务。然后我们发送一个DivideRequest,用客户端将9除以3,然后我们读取响应。响应显示商是3:

-------------------
|  response => 3  |
-------------------

路径和查询参数

一个请求处理程序不会直接访问路径和查询参数。相反,它们被自动转化为JSON对象。例如,一个POST到这个URL:

http://localhost:8086/api/1.0/divide/dividend/9/divisor/3

与上面DivisionClient代码中的POST请求完全相同。路径的dividend/9/divisor/3部分被转化为一个JSON对象,就像这样:

{
    "dividend": 9,
    "divisor": 3
}

microservlet处理这个JSON,就像它被发布一样。当POST-ing "平面 "请求对象(没有嵌套的对象)时,这个功能会很方便。请注意,当提供路径变量或查询参数时,请求的主体会被忽略。

OpenAPI

服务器上的"/docs "根路径通过Swagger提供了一个生成的OpenAPI规范。

OpenAPI可用的注释很少,但对简单的REST项目很有效。

注释目的
@OpenApiIncludeMember在规范中包括被注释的方法或字段。
@OpenApiExcludeMember将注释方法或字段从规范中排除。
@OpenApiIncludeMemberFromSuperType在规范中包括来自超类或超接口的成员。
@OpenApiIncludeType包括规范模式中的注解类型
@OpenApiRequestHandler提供关于请求处理方法*(onGet()*、onPost()onDelete())的信息。

代码

上面讨论的代码是kivakit-examples资源库中的一个工作实例。在调试器中追踪该代码可能会有启发。

KivaKit 微服务 API 可在开发分支的 kivakit-microservice模块的开发分支中。

<dependency>
    <groupId>com.telenav.kivakit</groupId>
    <artifactId>kivakit-microservice</artifactId>
    <version>${kivakit.version}</version>
</dependency>