Micronaut:面向未来的微服务和云原生应用框架

本文为翻译发表,转载需要注明来自公众号EAWorld。

作者:Zachary Klein

译者:白小白

原题:MICRONAUT: A JAVA FRAMEWORK FOR THE FUTURE, NOW

原文:

https://objectcomputing.com/resources/publications/sett/july-2018-micronaut-framework-for-the-future

全文7435字,阅读约需要18分钟

白小白:

这是一篇花费小白较长时间的译文,主要在于如何以零Java基础的视角来理解和表达文中的诸多概念以及保证后续示例应用的部分可以正常运行。

依赖注入、控制反转和面向切面编程,是Micronaut有别于Spring Boot这类传统框架的核心部分。关于这几个概念,我推荐不了解的同学浏览下面的文章,轻松易懂。

轻松理解AOP(面向切面编程)

https://blog.csdn.net/yanquan345/article/details/19760027

依赖注入的简单理解

https://www.cnblogs.com/alltime/p/6729295.html

友情提示,请注意文中小白的提示,有些段落如果没有按照教程,是可能导致尝试失败的,切记。

经测试可以成功运行示例代码的环境如下 :

SDKMAN 5.7.2+323

java version "1.8.0_181"

Using micronaut version 1.0.0.M4

祝大家玩的愉快。

一、导言

今年5月,OCI的一个开发团队发布了新的开源框架Micronaut的第一个里程碑版本。

Micronaut是JVM的应用程序框架,主要用以创建微服务云原生应用程序

可以理解,在一个似乎充斥着框架选项的行业中,开发者通常想要预先了解一个新框架带来了什么以及它提供了哪些独特的特性或功能。

本文的目的是:

  • 介绍microronaut背后的一些基本原理。
  • 强调使用框架的一些关键优势。
  • 介绍一个简单的应用程序,以全面了解框架的构造和编程风格。

二、内容精要

Micronaut是一个JVM框架,用于使用Java、Groovy或Kotlin来创建可伸缩的高性能应用。

它提供了包括但不限于以下的所有特性:

  • 提供高效率的编译时依赖注入(Dependency Injection,后文简称DI)容器
  • 提供一套基于Netty的反应式HTTP服务器和客户端
  • 提供一套云原生特性用以在构建微服务系统时提高开发人员的生产力

该框架从Spring和Grails获得灵感,提供了熟悉的开发流程,但是最小化了启动时间和内存使用。因此,Micronaut可以用于一系列传统MVC(Model/View/Controller)框架无能为力的场景:包括Android应用程序、无服务器函数、IOT部署和CLI应用程序等。

三、单体式应用的崛起

目前正在开发的大多数JVM Web应用程序都基于倡导MVC模式的框架,并提供依赖注入、面向切面编程(AOP)支持和易于配置等特性。

Spring Boot和Grails等框架依赖Spring IoC(反转控制)容器,使用反射机制在运行时分析应用程序类,然后将它们连接在一起来构建应用的依赖关系图。反射元数据还用于为事务管理等功能生成代理。

这些框架给开发人员带来了许多好处,包括提高生产力、减少冗余代码和创建更具表现力的应用程序代码。

许多此类框架是围绕单体应用设计的。单体应用是一个独立的程序,管理从底层数据库到前端UI的整个应用程序的堆栈,然后将应用程序打包为servlet容器等二进制文件,并部署到Tomcat、Glassfish等服务器上。在一个更完整的工作流程中,框架就可以引入这些嵌入式容器,从而使应用程序更具可移植性。

四、云化的微服务

今天,这些传统的应用程序架构正在被新的模式和技术所取代。

许多组织正在将所谓的单体应用程序分解为更小的、面向服务的应用程序,这些应用程序在分布式系统中协同工作。

新的体系结构模式要求通过多个功能受限、相互独立的微服务应用程序的交互来满足业务需求:.

跨服务边界的通信是微服务设计的关键,通常采用RESTful HTTP调用来完成。

然而,现代框架不仅需要简化开发,还需要简化运维。

现代应用程序比以往任何时候都更加依赖于云计算技术。

相较于自建服务器和数据中心并费心管理其健康状况,越来越多的组织将其应用程序部署到云端平台之上,用户不需要了解服务器的细节,就可以使用功能完备的工具和自动化手段对服务进行伸缩、重新部署和监控。

五、反射机制的问题

诚然,传统框架在很大程度上一直在紧跟行业的步伐,许多开发人员已经成功地使用这些构架构建了微服务并将其部署到云端。

然而,在此过程中,新架构和云环境的需求都暴露了一些潜在的痛点。对运行时反射(依赖注入和代理生成)机制的依赖带来了一些性能问题,包括启动、分析和连接应用程序所需的时间需求,以及加载和缓存这些元数据所需的内存需求。

更不幸的是,在给定的应用程序中,对这些问题的考量需要随着codebase的大小和资源需求的增加动态变化。

时间和内存都是在使用云平台过程中需要花费真金白银的资源。服务需要被回收,并以最小的延迟重新上线。而且服务的数量也在增加(在大规模系统上可能会增加到数百个)。很明显,对于每个服务的多个实例,在享用传统框架所带来的便利性的同时,需要支付相应的现实成本。

此外,许多云提供商正在提供无服务器平台,如AWS Lambda,其中应用程序简化为单一用途函数,用以组合和编排以执行复杂业务逻辑。

无服务器计算的轻量级、响应性和最小化的内存消耗的优势,让传统的、基于反射的框架的问题体现的更为突出。

六、更好的方法

Micronaut为微服务和云端应用设计,保留了MVC编程模型和传统框架的其他特性。这主要是得益于一个全新的DI/AOP容器,该容器在编译时而不是运行时提供依赖注入机制。

通过在代码中注释类和类成员,您可以使用与Spring非常相似的约定来表示应用程序的依赖关系和AOP行为;然而,在编译应用程序时就会完成对元数据的分析。此时,Micronaut将在原始代码之外生成额外的类,创建bean定义、拦截器和其他工件,以便在应用程序运行时启用DI/AOP行为。

提示:从技术上讲,这种编译时处理是通过使用Java注释处理器实现的,Micronaut用这些处理器来分析类以及创建相关的bean定义类。对于支持Groovy的框架来说,相关处理是使用AST变换进行的。

Micronaut实现了JSR 330 Java依赖项注入规范,在javax.inject包(如@Inject和@Singleton)之下,提供了语义注解,来表示DI容器中的类与类关系。

下面的清单显示了Micronaut DI的一个简单示例。

import javax.inject.*; 

interface Engine {
    int getCylinders();
    String start();
}

@Singleton
public class V8Engine implements Engine {
    int cylinders = 8;   
    
    String start() {
         return "Starting V8";
     }
}     

@Singleton
public class Vehicle {
    final Engine engine
    
    public Vehicle(Engine engine) {
        this.engine = engine;
    }
    
    String public start() {
        return engine.start();
    }
}

当应用程序运行时,将生成一个新的Vehicle实例和Engine接口,在本例中是V8Engine。

import io.micronaut.context.*; 
Vehicle vehicle = BeanContext.run().getBean(Vehicle);
System.out.println( vehicle.start() );

通过将DI容器的工作移到编译阶段,codebase的大小与启动应用程序所需的时间之间或者存储反射元数据所需的内存之间,不再有关联关系。

因此,用Java编写的Micronaut应用程序通常可以秒启。

白小白:

呃,经小白的实际测试,即使是一个Hello World,在Gradle环境下也需要6秒左右的时间,这还是第二次运行的情况,首次运行需要28秒左右。秒起多少有点夸张。当然也可能因为是在Laptop而非服务器端环境。

Gradle

> ./gradlew run 

Task :run 
16:21:32.511 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 842ms. Server Running: http://localhost:8080

Maven

> ./mvnw compile exec:exec
[INFO] Scanning for projects...
[INFO] --- exec-maven-plugin:1.6.0:exec (default-cli) @ my-java-app ---
16:22:49.833 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 796ms. Server Running: http://localhost:8080

用Groovy和Kotlin编写的应用程序可能需要超过1秒的时间,原因在于语言方面的开销,以及使用第三方类库(如Hibernate)增加了启动和内存需求。好在,无论是在启动时间还是内存需求方面,codebase的大小都不再是一个重要因素;编译后的字节码已经包含了运行和管理DI类所需的一切资源。

七、HTTP层

Micronaut的DI核心是微服务框架的一个重要部分,通过HTTP暴露服务和调用其他服务是微服务体系结构的另一个重要组成部分。

Micronaut的HTTP层,基于Netty建立,Netty提供了高性能的异步网络框架,反应事件驱动编程模型,以及对创建服务器-客户端应用的支持。

在微服务系统中,许多应用程序将同时扮演这两种角色:通过网络暴露数据的服务端和针对系统中其他服务提出请求的客户端。

与传统框架一样,Micronaut也包含了Controller为请求服务。下面是一个简单的Micronaut controller。

HelloController.java

import io.micronaut.http.annotation.*; 
@Controller("/hello")
public class HelloController {  
     @Get("/{name}")
     public String hello(String name) {
        return "Hello, " + name;
     }
} 

这个简单的例子演示了许多Java MVC框架使用的熟悉的编程模型。Controller只是带有方法的类,每个类都带有具备含义的注释,Micronaut使用这些注释在编译时创建必要的HTTP处理代码。

在微服务环境中,同样重要的是作为客户端与其他服务交互。

Micronaut提供了额外的属性,以使其HTTP客户端功能与服务器的功能相当,调用服务的代码与创建服务的代码看起来非常相似。

下面是一个简单的Micronaut客户端代码,它将调用上面提供的控制器端点。

HelloClient.java

import io.micronaut.http.client.Client;
import io.micronaut.http.annotation.*;

@Client("/hello")
public interface HelloClient { 

    @Get("/{name}")
    public String hello(String name);
}

HelloClient现在可以和运行在/hello URI的服务进行交互,在DI容器中创建客户端bean所需的所有代码,包括执行HTTP请求、绑定参数,甚至解析响应,都是在编译时生成的。

此客户端可以在示例应用程序中使用,这是一个单独的服务(假设URL设置正确或启用了服务发现),或者在如下所示测试类中使用。

HelloClientSpec.groovy

import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.* 

class HelloClientSpec extends Specification {
    //start the application
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer =  
ApplicationContext.run(EmbeddedServer) 
   
    //get a reference to HelloClient from the DI container
    @Shared
    HelloClient client = 
embeddedServer.applicationContext.getBean(HelloClient) 

    void "test hello response"() {
        expect:
        client.hello("Bob") == "Hello, Bob" 
    }
}           

由于客户端方法和服务器方法共享相同的签名,因此通过实现共享接口,可以轻松地在请求两端之间强制执行协议,该接口可以存储在跨微服务系统使用的共享库中。

在我们的例子中,HelloController和HelloClient都可从共享接口HelloOperations实现/扩展而来。

HelloOperations.java

import io.micronaut.http.annotation.*; 

public interface HelloOperations {
    @Get("/{name}")
    public String hello(String name);
}    

HelloClient.java

@Client("/hello")
public interface HelloClient extends HelloOperations {/*..*/ }

HelloController.java

@Controller("/hello")
public class HelloController extends HelloOperations {/*..*/ }

八、天生的反应性

反应式编程是Netty和Micronaut的核心概念。

上面的controller和client可以很容易的基于任何Reactive Streams实现来进行编写,例如RxJava 2.0。这允许您以完全非阻塞的方式(诸如Observable, Subscriber,和Single结构)来编写所有HTTP逻辑。

RxHelloController.java

import io.reactivex.*; 
@Controller("/hello")
public class RxHelloController {

    @Get("/{name}")
    public Single<String> hello(String name) {
        return Single.just("Hello, " + name);
    }
}

RxHelloClient.java

import io.reactivex.*; 

@Client("/hello")
public interface RxHelloClient {  

    @Get("/{name}")
    public Single<String> hello(String name);
}

九、天然的云原生

云原生应用程序被专门设计为在云计算环境中操作,与系统中的其他服务交互,并在其他服务变得不可用或没有响应时优雅地实现降级。

Micronaut提供了一整套的属性来使得构建云原生应用程序的过程非常愉快。

Micronaut为许多最常见的需求提供原生解决方案,而不是依赖第三方工具或服务。

让我们来看看其中的几个需求。

1、服务发现

服务发现意味着应用程序能够在集中的注册中心找到彼此,而无需在配置中查找URL或硬编码的服务器地址。

Micronaut将服务发现支持直接构建于@Client注释中,从而执行服务发现非常简单,只需提供正确的配置,然后使用“服务ID”来发现所需服务。

例如,下面的配置将Micronaut应用程序注册为Consul(一个分布式的服务发现和配置管理工具)实例,使用的服务ID为hello-world.

src/main/resources/application.yml

micronaut:
      application:
          name: hello-world
  consul:
    client:
      registration:
        enabled: true
      defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"

应用程序启动并向Consul注册后,客户端可以通过简单地在@Client注释中指定服务ID来查找服务。

@Client(id = "hello-world")
public interface HelloClient{
       //...
}

Micronaut目前支持Consul和Kubernetes,并计划支持更多的服务发现框架。

2、负载均衡

当注册同一服务的多个实例时,Micronaut提供一种“轮询调度”机制的负载平衡,通过对可用实例发出轮询请求,以确保没有实例被压垮或浪费。

这是一种客户端负载平衡机制,每个实例要么接受当前请求,要么将请求传递给服务的下一个实例,从而自动将负载分散到可用的实例中。

这种负载均衡方案是Micronaut内置的,免费提供给使用者。但是,Micronaut也支持替代实现,如,安装和配置Netflix Ribbon库来作为负载平衡策略。

src/main/resources/application.yml

ribbon:
       VipAddress: test 
       ServerListRefreshInterval: 2000

3、重试和断路器

当与分布式系统中的其他服务交互时,不可避免的是,在某些时候,事情不会按计划进行;也许某个服务会暂时停止,或者只是简单地放弃了一个请求。

Micronaut提供了许多工具来优雅地处理这些灾难性场景。

例如,Micronaut中的任何方法都可以用@Retryable注释来应用自定义的重试策略。当注释应用于@Client接口时,重试策略将应用于客户端中的每个请求方法。

@Retryable
@Client("/hello")
public interface HelloClient { /*...*/ }

默认情况下,@Retryable将尝试调用该方法三次,每次尝试之间有一秒的延迟。

当然,可以重写这些值,例如:

@Retryable( attempts = "5", delay = "2s" )
@Client("/hello")
public interface HelloClient { /*...*/ }

当然,如果对硬编码的方式不感冒,也可以配置中注入相关数值,如果没有提供配置,将使用默认值。

@Retryable( attempts = "${book.retry.attempts:3}",
    delay = "${book.retry.delay:1s}" )
@Client("/hello")
public interface HelloClient { /*...*/ }

@Retryable的一种更复杂的形式是@CircuitBreaker注释。和上面的行为模式略有不同,@CircuitBreaker将允许设定一个reset期间(默认情况下为30秒),在此时间窗口内,一定数量的请求在可能的死循环开始之前就会失败,被调用方法会立即失败,其内部的代码也不会执行。

这可以帮助防止陷入困境的服务或其他下游资源被请求淹没,给它们一个恢复的机会。

@CircuitBreaker( attempts = "3", reset = "20s")
@Client("/hello")
public interface HelloClient { /*...*/ }

十、构建Micronaut应用程序

真正了解一个框架的最好方法是上手实践,所以我们将用一个渐进的指南来结束对Micronaut的介绍,通过这个指南,你将构建你的第一个Micronaut应用程序。

作为附加题,我们还将更进一步将我们的“微服务”作为容器部署到云端,在本例中是Google计算引擎.

步骤1:安装Micronaut

Microronaut可以从GitHub代码安装,或者下载二进制文件本地安装。我们建议使用sdkman来进行安装。

如果还没有安装sdkman,则可以在任何基于Unix的shell中使用以下命令安装sdkman:

> curl -s "https://get.sdkman.io" | bash
> source "$HOME/.sdkman/bin/sdkman-init.sh"
> sdk version
SDKMAN 5.6.4+305

白小白:

安装过程需要使用zip和unzip,因此这两个应用需要预先安装,对于我本机的ubuntu 16.04,安装方式是 sudo apt-get install zip unzip。此外,sdk version可能会遇到临时的网络问题而提示失败,重试一下就好。

现在可以使用以下sdkman命令安装Micronaut。

(使用sdk list micronaut查看可用版本,请执行以下操作。目前最新的是1.0.0.M2.)

> sdk install micronaut 1.0.0.M2

白小白:

成文时,最新版本已经更新为1.0.0.RC1,本文尝试了M2和M4两个版本,并且指定版本号的部分并非必须,即默认安装最新版本。建议仍旧指定M2版本以顺利完成教程,因本文的示例是基于M2版本的,M4版本和M2版本使用上有一定差异,会导致示例代码的运行失败,后续会介绍。当然,可以通过指定版本号的方式,两个版本都安装,然后使用sdk default micronaut 版本号来切换当前版本。

通过运行mn -v。

mn -v
| Micronaut Version: 1.0.0.M2
| JVM Version: 1.8.0_171

白小白:

当然,既然是基于JVM的框架,在安装Micronaut前你本机先要安装JDK。另外,mn -v在M4版本下不会显示版本号,而是进入mn的交互式模式。M4显示版本号应该运行mn –version。

步骤2:创建项目

mn命令是Micronaut的CLI。您可以使用此命令创建新的Micronaut项目。

在本练习中,我们将创建一个现成的Java应用程序,但也可以通过添加-lang 标志来使用其他你喜欢的语言,如Groovy 或者 Kotlin (-lang groovy或-lang kotlin).

mn命令接受features标志,可以添加对项目中各种类库和配置的支持。可以通过运行mn profile-info services来查看所有可用的features。

我们要用spock标志在项目中添加对Spock测试框架的支持。运行以下命令:

mn create-app example.greetings -features spock
| Application created at /Users/dev/greetings

白小白:

在M4版本中,添加了-features spock的情况下会导致运行失败。因为在M4版本中,-features的正确写法是--features或者-f,其他诸如前文的-lang和后文的-build与此规则类似。

注意,我们可以为项目名称(greetings)提供一个默认的包前缀(example)。否则,项目名称将被用作默认包,此包将包含Application类和使用CLI命令生成的任何类,稍后我们会做介绍。

默认情况下,create-app命令将生成一个Gradle构建。如果您希望使用Maven作为构建工具,则可以使用-build标志。

此时,您可以使用Gradle的run命令运行应用程序。

./gradlew run
Starting a Gradle Daemon (subsequent builds will be faster) 

> Task :run
03:00:04.807 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 1109ms. Server Running: http://localhost:37619

注意,每次运行应用程序时都会随机选择服务器端口。当使用服务发现解决方案来定位实例时,这是有意义的,但是对于我们的练习来说,将端口号设置为一个已知的值(比如8080)更方便些。我们将在下面的步骤中这样做。

提示:如果希望使用IDE运行Micronaut项目,请确保IDE支持Java注释处理器,并为项目启用了这种支持。在IntelliJ IDEA中,相关设置在Preferences → Build, Execution, Deployment → Compiler → Annotation Processors → Enabled。

步骤3:配置

Micronaut中的默认配置格式是YAML,但也支持其他格式,包括Java属性文件、Groovy配置和JSON。

默认配置文件位于src/main/resources/application.yml。让我们编辑这个文件来设置我们的服务器端口号。

src/main/resources/application.yml

micronaut:  
      application:
                name: greetings
      server:
                port: 8080

如果重新启动应用程序,您将看到它继续运行http://localhost:8080.

步骤4:编写代码

在项目目录中,运行mn命令以交互模式启动Micronaut CLI。

> mn
| Starting interactive mode...
| Enter a command name to run. Use TAB for completion:
mn>

运行以下两个命令来生成控制器、客户端和服务bean。

白小白:

此处显然是笔误,实际上是3条命令。

mn> create-controller GreetingController
| Rendered template Controller.java to destination src/main/java/greetings/GreetingController.java
| Rendered template ControllerSpec.groovy to destination src/test/groovy/greetings/GreetingControllerSpec.groovy

mn> create-client GreetingClient
| Rendered template Client.java to destination src/main/java/greetings/GreetingClient.java

mn> create-bean GreetingService
| Rendered template Bean.java to destination src/main/java/demo/GreetingService.java

编辑生成的文件,如下面三个清单所示

src/main/java/example/GreetingController.java

package example; 

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.reactivex.Single;
import javax.inject.Inject; 

@Controller("/greeting")
public class GreetingController { 

    @Inject
    GreetingService greetingService; 
    
    @Get("/{name}")
    public Single<String> greeting(String name) {
        return greetingService.message(name);
    }
}    

.src/main/java/example/GreetingClient.java

package example; 

import io.micronaut.http.client.Client;
import io.micronaut.http.annotation.Get;
import io.reactivex.Single; 
@Client("greeting")
public interface GreetingClient {  

    @Get("/{name}")
    Single<String> greeting(String name);
}

.src/main/java/example/GreetingService.java

package example;

import io.reactivex.Single;
import javax.inject.Singleton; 
@Singleton
public class GreetingService { 

    public Single<String> message(String name) {
        return Single.just("Hello, " + name);
    }
}

在编写了控制器、客户端和服务类之后,如果我们再次运行应用程序,我们应该能够发出请求,如下面所示的curl命令。

> curl http://localhost:8080/greeting/Beth
Hello, Beth

让我们编辑生成的GreetingControllerSpec利用我们的客户端接口。

.src/test/groovy/example/GreetingControllerSpec.groovy

package example 

import io.micronaut.context.ApplicationContext
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification 

class GreetingControllerSpec extends Specification { 
    @Shared @AutoCleanup EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer)
    
    void "test greeting"() {
        given:
        GreetingClient client = embeddedServer.applicationContext.getBean(GreetingClient)    
        expect:
        client.greeting("Beth").blockingGet() == "Hello, Beth"
    }
}       

运行./gradlew test执行测试(如果启用了注释处理,也可以在IDE中执行测试)。

白小白:

此处,直接执行是会报错的,找不到greeting这个service,需要注释掉given:和expect:这两行,此外,在我的版本,成功测试后会有一个关于Gradle的Wanning,不影响后续尝试,可以忽略

./gradlew test 
BUILD SUCCESSFUL in 6s

步骤5:部署到云端

为了部署我们的应用程序,我们需要生成一个可运行的构建工件。运行Gradle任务shadowJar创建一个可执行的“fat”JAR文件。

> ./gradlew shadowJar

BUILD SUCCESSFUL in 6s
3 actionable tasks: 3 executed

使用java -jar命令来测试Jar文件是否正常运行。

java -jar build/libs/greetings-0.1-all.jar
03:44:50.120 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 847ms. Server Running: http://localhost:8080

接下来的几个步骤来自Google Cloud网站上的文档。进行如下操作前,你需要一个谷歌云账号并在设置中启用billing enabled。

Google云设置

1.在Google Cloud控制台 创建一个项目。

2.确保在API类库中启用了Compute Engine和Cloud Storage API.

3.安装Google Cloud SDK。运行gcloud init来初始化SDK并选择在步骤1中创建的新项目。

上传JAR包

1.创建一个新的Google存储bucket来存储JAR文件。在本例中的bucket名称是:greetings。

白小白:

几乎可以确定的是此处你一定会遇到“ServiceException: 409 Bucket greetings already exists.”的错误,因为geetings这个bucket名称已经被使用了。你需要改成其他的不会重复的名字,比如greetings-micronaut-当前日期。

> gsutil mb gs://greetings

2.上传greetings-all.jar归档到新的bucket。

gsutil cp build/libs/greetings-0.1-all.jar gs://greetings/greetings.jar

创建实例启动脚本

Google Compute允许使用Bash脚本提供一个新实例。在项目目录中创建一个名为instance-startup.sh。添加以下内容:

#!/bin/sh

# Set up instance metadata
PROJECTID=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google")
BUCKET=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/BUCKET" -H "Metadata-Flavor: Google") 

echo "Project ID: ${PROJECTID} Bucket: ${BUCKET}" 

# Copy the JAR file from the bucket
gsutil cp gs://${BUCKET}/greetings.jar . 

# Update and install/configure dependencies
apt-get update
apt-get -y --force-yes install openjdk-8-jdk
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java

# Start the application
java -jar greetings.jar

白小白:

注意,代码中一共有3处的${PROJECTID}和${BUCKET}变量要替换成实际的值,${PROJECTID}显然在本例中就是greetings,${BUCKET}就是刚刚上传的那个你设定的个性化的bucket名称

配置计算引擎

1.运行以下命令来创建Compute实例,使用instance-startup.sh脚本和在前面步骤中使用的bucket名。

gcloud compute instances create greetings-instance \
--image-family debian-9 --image-project debian-cloud \
--machine-type g1-small --scopes "userinfo-email,cloud-platform" \
--metadata-from-file startup-script=instance-startup.sh \
--metadata BUCKET=greetings --zone us-east1-b --tags http-server

2.实例将被初始化并立即启动。这可能需要几分钟。

3.在启动过程中隔一段时间运行以下命令以便查看实例日志。如果一切顺利,一旦这个过程完成,您应该会看到一条“Finished running startup scripts”的消息。

> gcloud compute instances get-serial-port-output greetings-instance --zone us-east1-b

白小白:

其实,这并不是一个必要步骤,如果实际运行了上面这条命令,产生的日志内容会占据N屏Console,建议没有任何问题的情况下,不要运行这条命令,此外,我在测试时并没有Finished…这句提示,代之以Created [https://www.googleapis.co…这样的提示,以及一个显示实例基本信息的列表,与第5步中用gcloud compute instances list得到的列表相同

4.运行以下命令在端口8080启用HTTP流量。

gcloud compute firewall-rules create default-allow-http-8080 \
--allow tcp:8080 --source-ranges 0.0.0.0/0  \
--target-tags http-server --description "Allow port 8080 access to http-server"

5.使用以下命令获取Compute实例的外部IP:

gcloud compute instances list
NAME                ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
greetings-instance  us-east1-b  g1-small                   10.142.0.3   35.231.160.118  RUNNING

现在应该能够使用EXTERNAL_IP访问应用.

> curl 35.231.160.118:8080/greeting/World
Hello, World

十一、优点和缺点

写作本文时,Micronaut还处于开发的早期阶段,还有许多工作要做。然而,在当前的里程碑版本中,已经有大量的功能可用。

除了本文讨论的特性外,Micronaut还支持以下内容:

  • 安全性(使用JWT、sessions或basic auth)
  • 管理端点
  • 使用Hibernate、JPA和GORM 自动配置数据访问权限
  • 通过@Scheduled支持批处理作业。
  • 配置共享
  • 其他

使用Micronaut进行开发的权威参考是http://docs.micronaut.io.

数量不多但不断增加的渐进教程可在http://guides.micronaut.io找到。此地址还包括Micronaut支持的所有三种语言的指南:Java、Groovy和Kotlin。

Gitter上的Micronaut社区频道(https://gitter.im/micronautfw/)是个好地方,在这里可以与已经在用框架构建应用程序的开发者交流心得,以及与Micronaut的核心开发团队交互。

时间将证明Micronaut将对微服务开发和整个行业产生什么影响,但似乎很明显,该框架已经在未来如何构建应用程序方面做出了重大贡献。

云原生应用的开发已经被广泛接受,Micronaut是基于这方面的考量而构建的全新工具。就像推动其创建的体系结构一样,Micronaut的灵活性和模块化将允许开发人员创建甚至其设计者都无法预见的系统。

JVM上的开发前景是光明的,即使有少许暗淡,Micronaut也肯定会发挥重要作用。一个重要的时代即将来临!

原文发布于微信公众号 - EAWorld(eaworld)

原文发表时间:2018-10-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏冷冷

Consul微服务的配置中心体验篇

Spring Cloud Consul 项目是针对Consul的服务治理实现。Consul是一个分布式高可用的系统,具有分布式、高可用、高扩展性 Consul ...

76460
来自专栏刘望舒

这一次彻底弄明白Gradle相关配置

1.1K20
来自专栏zhisheng

日志工具现状调研

  针对这类问题,对当前java比较流行的一些日志工具进行了调研,以期能够在未来的开发使用中做到全组代码风格统一,日志写得好对于我们开发调试,线上问题追踪等都有...

20120
来自专栏美团技术团队

Java NIO浅析

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到...

43190
来自专栏C/C++基础

Linux下离线手动下载安装C++开发环境

Linux下我们习惯了使用软件包管理器来安装我们需要的软件,比如Red Hat公司的Fedora、RHEL(Red Hat Enterprise Linux)和...

58620
来自专栏纯洁的微笑

Eureka 虽然闭源了,但注册中心还有更多选择:Consul 使用详解

在上个月我们知道 Eureka 2.0 闭源了,但其实对国内的用户影响甚小,一方面国内大都使用的是 Eureka 1.X 系列,另一方面

87230
来自专栏大数据架构师专家

namp 渗透测试-安装篇

nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端,并且推断计算机运行哪个操作系统。

15130
来自专栏菩提树下的杨过

intellij idea 高级用法之:集成JIRA、UML类图插件、集成SSH、集成FTP、Database管理

之前写过一篇IntelliJ IDEA 13试用手记 ,idea还有很多高大上的功能,易用性几乎能与vs.net媲美,反正我自从改用idea后,再也没开过ecl...

47450
来自专栏阿杜的世界

Java Web技术经验总结(二)

20930
来自专栏坚毅的PHP

ImageMagick and JMagick install on Mac OSX

接的遗留代码,在本地运行,有jmagick-6.4.0.jar 但是出现错误: javax.servlet.ServletException: java.lan...

45260

扫码关注云+社区

领取腾讯云代金券