java 开发 jvm_适用于Java开发人员的微服务:Java / JVM格局

java 开发 jvm

1.简介

在本教程的前一部分中,我们介绍了在构建微服务时广泛使用的多种通信方式。 现在该是通过讨论最流行且经过实践检验的Java库和框架来将这些知识付诸实践的时候了,这些库和框架可以用作您的微服务体系结构实现的基础。

尽管有许多足够古老的东西可以记住SOAP时代,但是我们不久将要讨论的许多框架都还很年轻,并且常常是自以为是。 选择哪一个最适合您可能是您将要尽早做出的最重要的决定。 除了JAX-RS规范(以及更通用的Servlet规范)之外,没有行业范围内的标准来保证JVM平台上不同框架和库之间的互操作性,因此请明智地进行调用。

因为每个框架或库都有自己的目标,理念,社区,发布周期,路线图,集成,可伸缩性和性能特征,所以在将一个框架或库升级到另一个框架上没有任何比较。 考虑到应用程序和组织的具体情况,有太多因素要考虑。

但是,几个宝贵的资源可能会很有帮助。 Awesome Microservices存储库是微服务架构相关原理和技术的绝佳清单。 同样, TechEmpowerWeb框架基准提供了许多有趣而有用的见解,它们涉及多个Web应用程序平台和框架,而不仅仅是JVM的性能。

2.保持休息

最拥挤的空间被框架和库占用,这些框架和库通过HTTP协议促进REST体系结构样式 。 几乎所有该类别的提名人都是非常成熟和成熟的品牌,已经在生产中使用了多年。

JAX-RS:企业中的RESTful Java

JAX-RS规范(也称为JSR-370 (先前在JSR-339JSR-311中概述))定义了一组Java API,用于开发根据REST体系结构样式构建的Web服务。 这是相当成功的工作,有许多可用的实现可供选择,并且可以说是企业界的第一选择。

JAX-RS API由Java注释驱动,通常可以很顺利地从一个框架移植到另一个框架。 此外,它与其他Java平台规范紧密集成,例如Java 上下文和依赖注入JSR-365 ), Bean验证JSR-380 ), JSON处理Java APIJSR-374 )等。

回到我们在本教程上一部分中讨论的可想象的库管理Web API,典型的(但非常简化的) JAX-RS Web服务实现可能看起来像这样:

@Path("/library")
public class LibraryRestService {
    @Inject private LibraryService libraryService;

    @GET
    @Path("/books")
    @Produces(MediaType.APPLICATION_JSON)
    public Collection<Book> getAll() {
        return libraryService.getBooks();
    }
    
    @POST
    @Path("/books")
    @Produces(MediaType.APPLICATION_JSON)
    public Response addBook(@Context UriInfo uriInfo, Book payload) {
        final Book book = libraryService.addBook(payload);
        
        return Response
            .created(
                uriInfo
                    .getRequestUriBuilder()
                    .path(book.getIsbn())
                    .build())
            .entity(book)
            .build();    }
    
    @GET
    @Path("/books/{isbn}")
    @Produces(MediaType.APPLICATION_JSON)
    public Book findBook(@PathParam("isbn") String isbn) {
        return libraryService
            .findBook(isbn)
            .orElseThrow(() -> new NotFoundException("No book found for ISBN: " + isbn));
    }
}

它可以在完全符合最新的JAX-RS 2.1规范( JSR-370 )的任何框架上工作,因此让我们从那里开始使用它。

Apache CXF

阿帕奇CXF ,一个开源的服务框架,庆祝其10 今年周年庆! Apache CXF使用前端编程API(例如JAX-WSJAX-RS)帮助构建和开发服务,它们可以使用多种协议(例如SOAPRESTSSE (甚至是CORBA )),并可以通过多种传输方式(例如HTTP)工作JMSJBI

是什么让阿帕奇CXF非常适合用于微服务是它与许多其他项目,特别是优秀的集成的事实: OpenAPI的合同驱动开发, 勇敢 / OpenTracing / 阿帕奇HTRACE分布式跟踪, JOSE / OAuth2用户 / ID连接的安全性。

Apache Meecrowave

Meecrowave是一个非常轻巧,易于使用的微服务框架专门建立在其他Apache项目之上: Apache OpenWebBeansCDI 2.0 ), Apache CXFJAX-RS 2.1 )和Apache JohnzonJSON-P )。 由于所有必需的零件都已经连接在一起,因此大大减少了开发时间。

高枕无忧

RedHat / JBoss的 RESTEasyJAX-RS 2.1规范的另一种完全认证的可移植实现。 RESTEasy框架的优点之一是与WildFly Application Server的紧密集成, 以防在您的上下文中可能很重要。

泽西岛

Jersey是一个开放源代码的生产质量框架,用于用Java开发RESTful Web服务 。 实际上,它用作JAX-RSJSR-370JSR-339JSR-311 )参考实现。 与其他框架类似, Jersey不仅限于JAX-RS实现,还提供了其他功能,扩展和实用程序,以进一步简化RESTful Web API和客户端的开发。

Dropwizard

Dropwizard是另一个伟大的Java框架,用于开发RESTful Web服务和API ,并着重于操作友好性和高性能。 它建立在Jersey框架的基础之上,并将整个Java生态系统中最好的品种库组合在一起。 从这个意义上讲,它固执己见,但同时又以其简单,稳定成熟和轻便着称

Dropwizard对复杂的配置,应用程序指标,日志记录,操作工具等提供了开箱即用的支持,使您和您的团队可以在最短的时间内发布高质量的Web服务。 https://www.dropwizard.io/1.3.5/docs

值得注意的是, Dropwizard确实为现代Java应用程序建立了检测和监视基线(您可能已经听说过由此而来的Metrics库),并且是构建微服务的不错选择。

Eclipse Microprofile:一开始就考虑微服务

在谈论Java Universe中的微服务时 ,不可能不提及Eclipse Foundation最近采取的举措,即MicroProfile

MicroProfile是一个基准平台定义,可为微服务架构优化Enterprise Java,并在多个MicroProfile运行时之间提供应用程序可移植性。 最初计划的基准是JAX-RS + CDI + JSON-P,社区的意图是在MicroProfile定义和路线图中发挥积极作用。 https://microprofile.io/faq

MicroProfile的主要目标是加快企业Java空间中的创新步伐,而传统上,该过程正处于非常缓慢的过程中。 当然值得关注。

SpringWebMvc / WebFlux

很久以前, Spring框架 (最初实现控制反转IoC )设计原则)的实施已经震撼了企业Java的世界,充满了可怕的框架和规范。 它提供了一种简单直接的方法来在Java应用程序中使用依赖项注入功能。

IoC依赖项注入仍然是Spring Framework的核心,但其框架之下有许多项目 ,因此如今它更像一个平台。 对于这一部分,我们感兴趣的是Spring Web MVC ,它是基于Servlet API构建的原始Web框架,并广泛用于传统的RESTful Web服务 ,例如我们的库管理API。

@RestController
@RequestMapping("/library")
public class LibraryController {
    @Autowired private LibraryService libraryService;
    
    @RequestMapping(path = "/books/{isbn}", method = GET, produces = APPLICATION_JSON_VALUE)
    public ResponseEntity<Book> findBook(@PathVariable String isbn) {
        return libraryService
            .findBook(isbn)
            .map(ResponseEntity::ok)
            .orElseGet(ResponseEntity.notFound()::build);
    }
    
    @RequestMapping(path = "/books", method = GET, produces = APPLICATION_JSON_VALUE)
    public Collection<Book> getAll() {
        return libraryService.getBooks();
    }

    @RequestMapping(path = "/books", method = POST, consumes = APPLICATION_JSON_VALUE)
    public ResponseEntity<Book> addBook(@RequestBody Book payload) {
        final Book book = libraryService.addBook(payload);
        
        return ResponseEntity
            .created(linkTo(methodOn(LibraryController.class).findBook(book.getIsbn())).toUri())
            .body(book);
    }
}

更不用说相对较新的Spring WebFlux项目,它是在响应堆栈非阻塞I / O之上构建的Spring Web MVC的对等项目。

创新,高效且取得巨大成功的Spring Framework如今已成为Java开发人员的第一选择,尤其是在微服务架构方面

Spark Java

Spark ,通常也称为Spark-Java,是为了消除与类似的超流行数据处理框架之间的混淆,它是一种微型框架,用于以最小的努力在Java中创建Web应用程序。 它严重依赖于通过Java 8 lambda表达式的功能而设计的富有表现力的简单DSL 。 实际上,这导致了相当紧凑和简洁的代码。 例如,这是我们的库管理API定义的一个偷偷摸摸的高峰:

path("/library", () -> {
    get("/books", 
        (req, res) -> libraryService.getBooks(),
        json()
    );
            
    get("/books/:isbn", 
        (req, res) -> libraryService
            .findBook(req.params(":isbn"))
            .orElseGet(() -> {
                res.status(404);
                return null;
            }), 
        json()
    );
            
    post("/books", 
        (req, res) -> libraryService
            .addBook(JsonbBuilder.create().fromJson(req.body(), Book.class)),
        json()
    );
});

除了Java外, Spark-Java还具有一流的Kotlin支持,尽管它主要用于创建REST API ,但它与许多模板引擎集成在一起。

Restlet

Restlet框架旨在帮助Java开发人员构建更好的遵循REST体系结构样式的 Web API。 它提供了非常强大的路由和过滤功能,并提供了许多扩展。 它具有非常独特的方式来将事物结构化和捆绑在一起。

public class BookResource extends ServerResource {
    @Inject private LibraryService libraryService;
    
    @Get
    public Book findBook() {
        final String isbn = (String) getRequest().getAttributes().get("isbn");
        return libraryService.findBook(isbn).orElse(null);
    }
}

public class BooksResource extends ServerResource  {
    @Inject private LibraryService libraryService;
    
    @Get
    public Collection<Book> getAll() {
        return libraryService.getBooks();
    }
    
    @Post("json")
    public Representation addBook(Book payload) throws IOException {
        return toRepresentation(libraryService.addBook(payload));
    }
}

这是资源与其URI (基本上是典型的路由器)之间的绑定。

final Router router = new Router(getContext());
router.attach("/library/books/{isbn}", BookResource.class);
router.attach("/library/books", BooksResource.class);

有趣的是, Restlet是为数不多的开源框架之一,该框架能够从简单的库成长为成熟的RESTful API开发平台

Vert.x

Eclipse FoundationVert.x项目是一个开源工具箱,用于在JVM平台上构建响应式应用程序。 它遵循了响应式范式,并从头开始设计为事件驱动和非阻塞的。

它具有许多不同的组件。 其中之一就是Vert.x-Web ,它被指定用于编写复杂的现代Web应用程序和基于HTTP微服务 。 下面的代码片段展示了我们在Vert.x-Web之上实现的图书馆管理Web API。

final LibraryService libraryService = ...;

final Vertx vertx = Vertx.vertx();
final HttpServer server = vertx.createHttpServer();
final Router router = Router.router(vertx);
        
router
    .get("/library/books")
    .produces("application/json")
    .handler(context ->
        context
            .response()
            .putHeader("Content-Type", "application/json")
            .end(Json.encodePrettily(libraryService.getBooks()))
    );
            
router
    .get("/library/books/:isbn")
    .produces("application/json")
    .handler(context ->
        libraryService
            .findBook(context.request().getParam("isbn"))
            .ifPresentOrElse(
                book -> context
                        .response()
                        .putHeader("Content-Type", "application/json")
                        .end(Json.encodePrettily(book)),
                () -> context
                        .response()
                        .setStatusCode(204)
                        .putHeader("Content-Type", "application/json")
                        .end()
            )
    );
        
router
    .post("/library/books")
    .consumes("application/json")
    .produces("application/json")
    .handler(BodyHandler.create())
    .handler(context -> {
        final Book book = libraryService
            .addBook(context.getBodyAsJson().mapTo(Book.class));
                
        context
            .response()
            .putHeader("Content-Type", "application/json")
            .end(Json.encodePrettily(book));
    });
        
server.requestHandler(router::accept);
server.listen(4567);

Vert.x的一些显着特征是高性能和模块化设计。 更重要的是,它非常轻巧,可扩展性很好,并且原生支持Java, JavaScriptGroovyRubyCeylonScalaKotlin

播放框架

Play是一种用于Java和Scala的高速,高产的Web框架。 它基于轻量级,无状态,对Web友好的体系结构,并基于Akka Toolkit构建。 尽管Play是具有异常强大的模板引擎的成熟框架,但它也非常适合RESTful Web服务开发。 我们的图书馆管理Web API可以在Play中轻松设计。

GET    /library/books           controllers.LibraryController.list
GET    /library/books/:isbn     controllers.LibraryController.show(isbn: String)
POST   /library/books           controllers.LibraryController.add
public class LibraryController extends Controller {
    private LibraryService libraryService;

    @Inject
    public LibraryController(LibraryService libraryService) {
        this.libraryService = libraryService;
    }
    
    
    public Result list() {
        return ok(Json.toJson(libraryService.getBooks()));
    }

    public Result show(String isbn) {
        return  libraryService
            .findBook(isbn)
            .map(resource -> ok(Json.toJson(resource)))
            .orElseGet(() -> notFound());
    }
    
    public Result add() {
        JsonNode json = request().body().asJson();
        final Book book = Json.fromJson(json, Book.class);
        return created(Json.toJson(libraryService.addBook(book)));
    }
}

Play能够同时服务于后端( RESTful )和前端(例如使用AngularReactVue.js )端点,换句话说,将其变为全栈,这对于使用单个框架实现服务而言可能是一种有吸引力的产品(尽管应非常谨慎地做出此类决定)。

Akka HTTP

Akka HTTP是令人惊叹的Akka Toolkit系列的一部分,提供了在actor模型之上实现的完整的服务器端和客户端HTTP堆栈。 它不是一个成熟的Web框架(例如Play ),而是专门为管理基于HTTP的服务而设计的。 与其他框架类似, Akka HTTP拥有自己的DSL,可以优雅地定义RESTful Web API端点。 尝试的最佳方法是创建我们的库管理API定义。

public class LibraryRoutes extends AllDirectives {
    private final LibraryService libraryService;

    // ...    
    
    public Route routes() {
        return route(
            pathPrefix("library", () ->
                pathPrefix("books", () ->
                    route(
                        pathEndOrSingleSlash(() ->
                            route(
                                get(() ->
                                    complete(StatusCodes.OK, libraryService.getBooks(), Jackson.marshaller())
                                ),
                                post(() ->
                                    entity(
                                        Jackson.unmarshaller(Book.class),
                                        payload -> complete(StatusCodes.OK, libraryService.addBook(payload), Jackson.marshaller())
                                    )
                                )
                            )
                        ),
                        path(PathMatchers.segment(), isbn -> 
                            route(
                                get(() -> 
                                    libraryService
                                        .findBook(isbn)
                                        .map(book -> (Route)complete(StatusCodes.OK, book, Jackson.marshaller()))
                                        .orElseGet(() -> complete(StatusCodes.NOT_FOUND))
                                )
                            )
                        )
                    )
                )
            )
        );
    }
}

Akka HTTP具有对Java和Scala的一流支持,通常是构建RESTful Web服务和可伸缩微服务体系结构的绝佳选择。

微型船

Micronaut是一个基于JVM的现代全栈框架,用于构建模块化,易于测试的微服务应用程序。 它是真正的多语种(从JVM的角度来说),并提供对Java, GroovyKotlin的开箱即用的支持。

Micronaut的重点是对React式编程范例和编译时依赖注入的一流支持。 这是Micronaut中我们的图书馆管理Web API声明的框架。

@Controller("/library")
public class LibraryController {
    @Inject private LibraryService libraryService;
    
    @Get("/books/{isbn}")
    @Produces(MediaType.APPLICATION_JSON)
    public Optional<Book> findBook(String isbn) {
        return libraryService.findBook(isbn);
    }
    
    @Get("/books")
    @Produces(MediaType.APPLICATION_JSON)
    public Observable<Book> getAll() {
        return Observable.fromIterable(libraryService.getBooks());
    }
    
    @Post("/books")
    @Consumes(MediaType.APPLICATION_JSON)
    public HttpResponse<Book> addBook(Book payload) {
        return HttpResponse.created(libraryService.addBook(payload));
    }
}

与其他人相比, Micronaut是一个非常年轻但很有前途的框架,专注于现代编程。 这是一个崭新的开始,多年来没有积累行李。

3. GraphQL,新力量

GraphQL的普及正在缓慢但稳定地增长。 尽管Java开发人员没有太多选择,但事实证明,它是解决各种各样问题的必不可少的工具。 在本节中,我们将使用与教程上一部分讨论的GraphQL模式相同的内容 ,为方便起见,在下面重复进行。

schema {
  query: Query
  mutation: Mutation
}

type Book {
  isbn: ID!
  title: String!
  year: Int
}

type Query {
  books: [Book]
  book(isbn: ID!): Book
}

type Mutation {
  addBook(isbn: ID!, title: String!, year: Int): Book
  updateBook(isbn: ID!, title: String, year: Int): Book
  removeBook(isbn: ID!): Boolean
}

西班牙果酒

桑格利亚GraphQL实施斯卡拉 。 这是一个了不起的框架,拥有活跃的社区,并且与Akka HTTP和/或Play框架无缝集成。 尽管目前它不提供Java友好的API,但是仍然值得一提。 例如,通过沿代码中的解析器定义架构,采取了一些不同的方法。

object SchemaDefinition {
  val BookType = ObjectType(
    "Book", "A book.", fields[LibraryService, Book](
      Field("isbn", StringType, Some("The book's ISBN."), resolve = _.value.isbn),
      Field("title", StringType, Some("The book's title."), resolve = _.value.title),
      Field("year", IntType, Some("The book's year."), resolve = _.value.year)
    ))
    
  val ISBN = Argument("isbn", StringType, description = "ISBN")
  val Title = Argument("title", StringType, description = "Book's title")
  val Year = Argument("year", IntType, description = "Book's year")

  val Query = ObjectType(
    "Query", fields[LibraryService, Unit](
      Field("book", OptionType(BookType),
        arguments = ISBN :: Nil,
        resolve = ctx ⇒ ctx.ctx.findBook(ctx arg ISBN)),
      Field("books", ListType(BookType),
        resolve = ctx ⇒  ctx.ctx.getBooks())
    ))

  val Mutation = ObjectType(
    "Mutation", fields[LibraryService, Unit](
      Field("addBook", BookType,
        arguments = ISBN :: Title :: Year :: Nil,
        resolve = ctx ⇒ ctx.ctx.addBook(Book(ctx arg ISBN, ctx arg Title, ctx arg Year))),
      Field("updateBook", BookType,
        arguments = ISBN :: Title :: Year :: Nil,
        resolve = ctx ⇒ ctx.ctx.updateBook(ctx arg ISBN, Book(ctx arg ISBN, ctx arg Title, ctx arg Year))),
      Field("removeBook", BooleanType,
        arguments = ISBN :: Nil,
        resolve = ctx ⇒ ctx.ctx.removeBook(ctx arg ISBN))
    ))
    
   val LibrarySchema = Schema(Query, Some(Mutation))
}

尽管代码优先模式开发存在一些优缺点,但在某些微服务体系结构实现中它可能是一个很好的解决方案。

graphql-java

容易猜测, graphql-javaJava中的GraphQL实现。 它与Spring Framework以及任何其他Servlet兼容的框架或容器都具有很好的集成。 对于像我们这样的简单GraphQL模式,实现仅是定义解析器的问题。

public class Query implements GraphQLQueryResolver {
    private final LibraryService libraryService;
    
    public Query(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
    
    public Optional<Book> book(String isbn) {
        return libraryService.findBook(isbn);
    }
    
    public List<Book> books() {
        return new ArrayList<>(libraryService.getBooks());
    }
}
public class Mutation implements GraphQLMutationResolver {
    private final LibraryService libraryService;
    
    public Mutation(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
        
    public Book addBook(String isbn, String title, int year) {
        return libraryService.addBook(new Book(isbn, title, year));
    }
    
    public Book updateBook(String isbn, String title, int year) {
        return libraryService.updateBook(isbn, new Book(isbn, title, year));
    }
    
    public boolean removeBook(String isbn) {
        return libraryService.removeBook(isbn);
    }
}

这就是字面上的意思。 如果您正在考虑在微服务体系结构的部分或全部服务中使用GraphQL ,那么graphql-java可能是一个坚实的基础。

4. RPC样式

RESTfulGraphQL相比, RPC对话的效率(尤其是服务到服务的通信)确实难以匹敌GooglegRPC框架在这里起了领导作用,但这并不是唯一的参与者。

我们将看到,许多RPC系统都是基于定义服务协定的思想构建的:在Java中,它通常是带注释的接口定义。 服务器端实现此接口并通过电线公开它,而在客户端,此接口用于获取代理或存根。

java-grpc

在本教程前一部分中,我们简要浏览了gRPC通用概念,但是在本节中,我们将讨论其Java实现– java-grpc 。 由于几乎所有内容都是根据协议缓冲区服务定义为您生成的,因此,留给开发人员的唯一事情就是提供相关的服务实现。 这是我们的库管理服务的gRPC版本。

static class LibraryImpl extends LibraryGrpc.LibraryImplBase {
    private final LibraryService libraryService;
        
    public LibraryImpl(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
        
    @Override
    public void addBook(AddBookRequest request, StreamObserver<Book> responseObserver) {
        final Book book = Book.newBuilder()
            .setIsbn(request.getIsbn())
            .setTitle(request.getTitle())
            .setYear(request.getYear())
            .build();

        responseObserver.onNext(libraryService.addBook(book));
        responseObserver.onCompleted();
    }
        
    @Override
    public void getBooks(Filter request, StreamObserver<BookList> responseObserver) {
        final BookList bookList = BookList
            .newBuilder()
            .addAllBooks(libraryService.getBooks())
            .build();
        responseObserver.onNext(bookList);
        responseObserver.onCompleted();
    }
        
    @Override
    public void updateBook(UpdateBookRequest request, StreamObserver<Book> responseObserver) {
        responseObserver.onNext(libraryService.updateBook(request.getIsbn(), request.getBook()));
        responseObserver.onCompleted();
    }
        
    @Override
    public void removeBook(RemoveBookRequest request, StreamObserver<Empty> responseObserver) {
        libraryService.removeBook(request.getIsbn());
        responseObserver.onCompleted();
    }
}

值得一提的是, 协议缓冲区是默认但不是唯一的序列化机制, gRPC也可以与JSON编码一起使用。 总的来说, gRPC表现出色,并且在微服务架构中实现服务到服务的通信无疑是一个安全的选择。 但是还有更多,敬请期待grpc-web指日可待。

React性gRPC

近年来, React式编程正逐渐进入主流。 Reactive gRPC是一组库,用于增强gRPC以与Reactive Streams实现一起使用。 简而言之,它只是针对您选择的库( 截至目前的RxJava 2Spring Reactor )生成替代性gRPC绑定,其他所有内容几乎保持不变。 为了证明这一点,让我们看一下使用Reactive Streams API的LibraryImpl实现。

static class LibraryImpl extends RxLibraryGrpc.LibraryImplBase {
    private final LibraryService libraryService;
        
    public LibraryImpl(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
        
    @Override
    public Single<Book> addBook(Single<AddBookRequest> request) {
        return request
            .map(r -> 
                Book
                    .newBuilder()
                    .setIsbn(r.getIsbn())
                    .setTitle(r.getTitle())
                    .setYear(r.getYear())
                    .build())
            .map(libraryService::addBook);
    }
        
    @Override
    public Single<BookList> getBooks(Single<Filter> request) {
        return request
            .map(r -> 
                BookList
                    .newBuilder()
                    .addAllBooks(libraryService.getBooks())
                    .build());
    }
        
    @Override
    public Single<Book> updateBook(Single<UpdateBookRequest> request) {
        return request
            .map(r -> libraryService.updateBook(r.getIsbn(), r.getBook()));
    }
        
    @Override
    public Single<Empty> removeBook(Single<RemoveBookRequest> request) {
        return request
            .map(r -> {
                libraryService.removeBook(r.getIsbn());
                return Empty.newBuilder().build();
            });
    }
}

公平地说, 响应式gRPC并不是成熟的gRPC实现,而是java-grpc的出色补充。

Akka gRPC

Akka工具箱中的另一个很棒的工具是Akka gRPC,它提供了对在Akka Streams (通常是Akka Toolkit )之上构建流gRPC服务器和客户端的支持。 基于Java的实现依赖于标准库中的CompletionStage ,并且使用起来非常简单。

public class LibraryImpl implements Library {
    private final LibraryService libraryService;
    
    public LibraryImpl(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
    
    @Override
    public CompletionStage<Book> addBook(AddBookRequest in) {
        final Book book = Book
            .newBuilder()
            .setIsbn(in.getIsbn())
            .setTitle(in.getTitle())
            .setYear(in.getYear())
            .build();
        
        return CompletableFuture.completedFuture(libraryService.addBook(book));
    }

    @Override
    public CompletionStage<BookList> getBooks(Filter in) {
        return CompletableFuture.completedFuture(
            BookList
                .newBuilder()
                .addAllBooks(libraryService.getBooks())
                .build());
    }
    
    @Override
    public CompletionStage<Book> updateBook(UpdateBookRequest in) {
        return CompletableFuture.completedFuture(libraryService.updateBook(in.getIsbn(), in.getBook()));
    }
    
    @Override
    public CompletionStage<Empty> removeBook(RemoveBookRequest in) {
        libraryService.removeBook(in.getIsbn());
        return CompletableFuture.completedFuture(Empty.newBuilder().build());
    }
}

Akka gRPCAkka Toolkit的新成员,目前处于预览模式。 它可能已经在今天使用,但肯定会在将来发生一些变化。

阿帕奇·达博(Apache Dubbo)

Apache Dubbo是一个高性能的,基于Java的开源RPC框架,目前由Apache Software Foundation进行孵化,但最初是在阿里巴巴开发的。 我们的库服务可以仅用几行代码即可启动并运行。

final ServiceConfig serviceConfig = new ServiceConfig();
serviceConfig.setApplication(new ApplicationConfig("library-provider"));
serviceConfig.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234"));
serviceConfig.setInterface(LibraryService.class);
serviceConfig.setRef(new LibraryServiceImpl());
serviceConfig.export();

它纯粹是面向Java的,因此,如果您打算构建多语言的微服务体系结构Apache Dubbo可能无法从本地帮助您,而是通过其他集成,例如RPC over RESTHTTP RPC

Finatra和Finagle

欺骗RPC库和Finatra ,建立在它之上的服务框架,在出生的Twitter后不久开源。

Finagle 是JVM的可扩展RPC系统,用于构建高并发服务器。 Finagle为多种协议实现了统一的客户端和服务器API,并旨在实现高性能和并发性。 https://github.com/twitter/finagle

Finatra 是一个轻量级框架,用于在 TwitterServer Finagle 之上构建快速,可测试的Scala应用程序 https://github.com/twitter/finatra

它们都是基于Scala的,并在生产中得到积极使用。 Finagle是最早使用Apache Thrift进行服务生成和二进制序列化的库之一。 让我们从教程上一部分中获取库服务IDL并将其实现为Finatra服务(通常,大多数脚手架代码都是由我们生成的)。

@Singleton
class LibraryController @Inject()(libraryService: LibraryService) extends Controller with Library.BaseServiceIface {
  override val addBook = handle(AddBook) { args: AddBook.Args =>
    Future.value(libraryService.addBook(args.book))
  }
  
  override val getBooks = handle(GetBooks) { args: GetBooks.Args =>
    Future.value(libraryService.getBooks())
  }
  
  override val removeBook = handle(RemoveBook) { args: RemoveBook.Args =>
    Future.value(libraryService.removeBook(args.isbn))
  }
  
  override val updateBook = handle(UpdateBook) { args: UpdateBook.Args =>
    Future.value(libraryService.updateBook(args.isbn, args.book))
  }
}

Finagle的显着特征之一是对监视和诊断的分布式跟踪和统计数据的开箱即用支持,这是在生产中运行微服务的宝贵见解。

5.消息和事件

微服务架构中 ,通常在许多松散耦合的分布式系统中,某种形式的消息和事件传递是基本的构建块之一。 在本节中,我们将讨论一些框架,并概述可以独立于所选框架使用的多种消息传递解决方案。

轴突框架

Axon是一个轻量级的开源Java框架,用于构建可扩展的,可扩展的事件驱动的应用程序。 它是在实践中采用领域驱动设计DDD )和命令与查询责任隔离CQRS )的合理体系结构原理的先驱之一。

拉各姆

Lagom是一个自以为是的开源框架,用于在Java或Scala中构建响应式微服务系统。 Lagom站在Akka ToolkitPlay巨头的肩膀上 框架 ,两项经过验证的技术,已在许多最苛刻的应用程序中经过了生产测试。 它根据域驱动设计DDD ), 事件源以及命令和查询责任隔离CQRS )的原理进行设计 ,并强烈鼓励使用这些模式。

阿卡

Akka是一个工具包,用于为Java和Scala构建高度并发,分布式和弹性消息驱动的应用程序。 如我们所见, Akka作为其他几个高级框架(例如Akka HTTPPlay框架 )的基础,但是它本身就是构建可分解​​为独立参与者的 微服务的好方法。 图书馆管理人员就是这种解决方案的一个例子。

public class LibraryActor extends AbstractActor {
    private final LibraryService libraryService;
    
    public LibraryActor(final LibraryService libraryService) {
        this.libraryService = libraryService;
    }
    
    @Override
    public Receive createReceive() {
        return receiveBuilder()
            .match(GetBooks.class, e -> 
                getSender().tell(libraryService.getBooks(), self()))
            .match(AddBook.class, e -> { 
                final Book book = new Book(e.getIsbn(), e.getTitle());
                getSender().tell(libraryService.addBook(book), self());
            })
            .match(FindBook.class, e -> 
                getSender().tell(libraryService.findBook(e.getIsbn()), self()))
            .matchAny(o -> log.info("received unknown message"))
            .build();
    }
}

Akka参与者之间的通信非常有效,并且不是基于HTTP协议的(首选传输方式是Aeron ,我们在本教程的上半部分已经简要讨论过)。 Akka Persistence模块使有状态的参与者可以保留其内部状态并在以后恢复它。 使用Akka实施微服务架构时,您可能会遇到某些复杂性,但总的来说,这是一个可靠的可靠选择。

零MQ

ZeroMQ不是典型的消息传递中间件。 它是完全无代理的(最初, ZeroMQ中前缀被称为“零代理”)。

ZeroMQ (也称为ØMQ,0MQ或zmq)看起来像一个可嵌入的网络库,但是却像一个并发框架。 它为您提供套接字,这些套接字可在各种传输方式(例如进程内,进程间,TCP和多播)中承载原子消息。 您可以使用扇出,发布-订阅,任务分配和请求-回复等模式将套接字从N到N连接。 它足够快,可以成为集群产品的基础。 它的异步I / O模型为您提供了可扩展的多核应用程序,这些应用程序是作为异步消息处理任务而构建的。 它具有多种语言API,并且可以在大多数操作系统上运行。 http://zguide.zeromq.org/page:all#ZeroMQ-in-a-Hundred-Words

它被广泛用于必须实现低延迟的应用程序和服务中。 这些就是微服务体系结构ZeroMQ可能有很大帮助的地方。

阿帕奇·卡夫卡

Apache Kafka构建分布式日志系统的想法开始,已经扩展到了分布式流平台之外。 它是水平可伸缩的,容错的,快速的,并且能够消化大量的消息(或事件)。

Apache Kafka的超高人气(有充分的理由)造成了许多其他消息代理被遗忘并且不受欢迎地逐渐消失的影响。 Apache Kafka不太可能无法跟上您的微服务体系结构实现的需求,但是更简单的选择通常可能是一个答案。

RabbitMQ和Apache Qpid

RabbitMQApache Qpid是使用AMQP协议的消息代理的经典示例。 除了RabbitMQ是用Erlang编写的事实而闻名外,没有什么好说的了。 两者都是开源的,是充当服务之间消息传递主干的理想选择。

Apache ActiveMQ

Apache ActiveMQ是最古老,功能最强大的开源消息传递解决方案之一。 它支持多种协议(包括AMQPSTOMPMQTT ),同时完全符合Java消息服务JMS 1.1 )规范。

有趣的是, Apache ActiveMQ框架下隐藏了许多不同的消息代理。 ActiveMQ Artemis就是其中之一,其目标是成为一个多协议,可嵌入,非常高性能的集群式异步消息传递系统。

另一个是ActiveMQ Apollo ,它是一项开发工作,旨在提供更快,更可靠且易于维护的消息传递代理。 它是在原始Apache ActiveMQ的基础上构建的,它具有截然不同的线程和消息调度体系结构。 尽管前景很好,但似乎已被放弃。

Apache ActiveMQ很可能具有您需要的所有功能,以使微服务可靠地传递消息。 同样, JMS支持在企业界可能是一个重要的好处。

Apache RocketMQ

Apache RocketMQ是一个开放源代码的分布式消息传递和流数据平台(这是Alibaba的另一个贡献)。 它旨在实现极低的延迟,高可用性和巨大的消息容量。

导航键

NATS是用于云原生应用程序,IoT消息传递和微服务架构的简单,高性能的开源消息传递系统。 它实现了高度可伸缩且优雅的发布-订阅消息分发模型。

NSQ

NSQ是一个开源实时分布式消息传递平台,旨在大规模运行并每天处理数十亿条消息。 它还遵循无代理模型,因此没有单点故障,支持高可用性和水平可伸缩性。

6.全力以赴

有某些类的库的唯一意图是将许多不同的通信通道无缝地桥接在一起。 总的来说,它们被称为集成框架,并且受到了很棒的《 企业集成模式》一书的启发。

阿帕奇骆驼

Apache Camel是功能强大且成熟的开源集成框架。 它是一个令人惊讶的小型库,具有最少的依赖关系集,并且可以轻松嵌入任何Java应用程序中。 它抽象了简洁的API层背后使用的传输类型,该API层允许与现成的300多个组件进行交互。

Spring整合

Spring IntegrationSpring项目产品组合的另一个重要成员,可实现轻量级消息传递以及与外部系统的集成。 它主要用于基于Spring的应用程序和服务中,可与所有其他Spring项目提供出色的互操作性。

Spring Integration 的主要目标是为构建企业集成解决方案提供一个简单的模型,同时保持关注点的分离,这对于生成可维护的,可测试的代码至关重要。 https://spring.io/projects/spring-integration

如果您的微服务是基于Spring框架构建的,那么进行Spring集成是一个合理的选择(以防其需求合理且适合整个体系结构)。

7.那么云呢?

在本教程的这一部分中,我们讨论了开源库和框架,这些库和框架可以在内部部署或云中使用。 它们通常与供应商无关,但是许多云提供商对一个或另一个框架有自己的偏见。 不仅如此,除了提供自己的托管服务(特别是在消息传递和数据流空间中)之外,云供应商还大力吸引了无服务器计算 ,主要是以功能即服务的形式

8.但是还有更多……

公平地说,有太多不同的库和框架可以讨论。 我们一直在讨论使用最广泛的应用程序,但还有很多。 让我们简要地提及其中一些。

OSGi及其分布式副本DOSGi是用Java构建模块化系统和平台的唯一真实方法。 尽管这不是一个简单的处理方法,但它可能非常适合于实现微服务

RxNetty是用于Netty的相当底层的React式扩展适配器,如果您需要开销非常低的引擎,则非常有用。

Rest.li (来自Linkedin )是一个框架,用于使用动态发现和简单的异步API构建健壮的,可扩展的RESTful Web服务体系结构。

Apache Pulsar是最初由Yahoo开发的用于服务器到服务器消息传递的多租户,高性能,极低延迟的解决方案。

9. Java / JVM景观–结论

在本教程的这一部分中,我们分页介绍了许多不同的库和框架,这些库和框架如今已用于在Java(通常是JVM)中构建微服务 。 他们每个人都有自己的位置,但这并没有使决策过程变得更加容易。 重要的是,当今的体系结构可能无法反映明天的现实:您必须选择可以在未来几年内随微服务扩展的堆栈。

10.下一步是什么

在本教程的下一部分中,我们将讨论monoglot与polyglot 微服务,并概述参考应用程序,以作为我们将来主题的基础。

完整的示例项目可供下载

翻译自: https://www.javacodegeeks.com/2018/09/microservices-java-developers-java-jvm-landscape.html

java 开发 jvm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值