Java微服務開發指南 -- 使用WildFly Swarm構建微服務
使用WildFly Swarm構建微服務
我們最後介紹一個新的微服務框架,它構建在支持分層且可靠的JavaEE
技術棧上(使用JBoss WildFly 應用服務器),WildFly Swarm是一個完全兼容WildFly應用服務器,它基於可重用的組件,這裏稱為元件(fractions)來組成微服務應用。組裝這些元件和你使用maven或者gradle去添加依賴一樣簡單,你隻需要聲明元件,WildFly Swarm將會幫助你完成後續的工作。
應用服務器和JavaEE
在企業級Java應用的領域耕耘了快20年了,WildFly(以前叫JBoss Application Server)作為一個開源的Java應用服務器在市場上出現,企業在JavaEE
技術棧上的投入非常巨大(不論是開源還是專有的供應商),包括培訓、工具開發、管理等方麵。JavaEE
通常都是能夠幫助開發人員構建分層的應用,因為它提供了諸如:servlets/JSP
、transactions
、組件模型、消息以及持久化等技術。JavaEE
應用在部署時,將會打包成為EARs(包括了WARs或者JARs以及配置),一旦你完成了打包,你就需要找到一個應用服務器,然後安裝。你可以利用應用服務器的高階特性,比如:動態部署或者重複部署(雖然這些在生產環境上用的比較少,但是在開發態比較有用),同時你的包也利用了應用服務器的特性,隻會包含必要的jar包,變得非常輕,一般隻會包含所需要的業務邏輯。雖然應用的包變小了,但是應用服務器卻變得很臃腫,因為它不得不包含應用所有可能需要的依賴。應用服務器中的每個JavaEE
組件都會極力優化自己的依賴,同時它們之間也會相互隔離。
應用服務器在一個實例中提供了管理、部署以及配置多個應用的唯一入口,一般情況下為了提高可用性,會在不同的節點上部署多個實例。當越來越多的應用部署到一個應用服務器實例上後,問題開始出現,一個進程,一個JVM,很容易出問題。如果遇到多個團隊開發的不同應用,都部署在一個應用服務器上,不同的應用類型、應用開發周期的不同、不同應用對於性能和SLA的要求,將會讓情況變得更糟。相比微服務架構所提供的快速響應變化、創新以及自治,JavaEE
應用這種將所有應用部署在單點、共享的方式就顯得過於笨拙,不僅僅如此,考慮在一個單點去管理和監控多個應用就顯得非常複雜。單個JVM好管理,可是在一個JVM裏麵放置多個應用就不那麼好管理了,當我們在這個單點上使用昂貴的工具進行檢測和調試找問題的時候,你就會更加感受這種痛苦了。一個解決方式就是在一個應用服務器中隻部署一個應用。
雖然微服務不屑於JavaEE
環境下的開發,但是不代表組件模型、APIs以及JavaEE
技術沒有價值。我們仍舊能夠使用持久化、事務、安全以及依賴注入等特性,我們如何將JavaEE
這些技術帶入到微服務中呢?WildFly Swarm就是用來做這個的。
WildFly Swarm會根據你的pom.xml
或者gradle file
計算決定你需要何種JavaEE
依賴,比如:CDI、新消息或者servlet
,然後會將應用打包為一個統一的jar(就像Spring Boot和Dropwizard一樣),這樣打包的應用就包含了最小化的JavaEE
環境。這個過程叫拚裝剛好夠用的JavaEE
環境,它能讓你繼續使用JavaEE
的API,而自由的選擇使用微服務的方式運行,或者部署到傳統的應用服務器中。你甚至可以將一個已經存在的WAR工程,通過WildFly Swarm將其構建成為包含了元件的微服務,而這種強大的能力使得你可以迅速的將一個已有的項目轉化成為一個微服務部署模式的應用。
開始
一般有三種方式使用WildFly Swarm,第一種是創建一個空的maven或者gradle項目,然後手動的添加依賴和maven插件。另一種就是使用類似Spring Initializer的控製台 -- WildFly Swarm Generator web console,最後一種是使用jboss-forge
。我們強烈的建議使用jboss-forge
來進行工程的創建,從完整性上考慮,我們會創建一個簡單的工程,同時jboss-forge
有插件支持流行的Java IDE,比如:Eclipse、Netbeans和IDEA。
香草Java工程
如果你有一個已經存在的Java工程,你可以通過修改一下pom.xml
來讓其變為一個WildFly Swarm,首先添加一個WildFly Swarm插件。
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
如果項目想使用JavaEE
的依賴,可以選擇依賴WildFly DOM(bill of materials),在<dependencyManagement>
元素下增加以下內容:
<dependencyManagement>
<dependencies>
<!-- JBoss distributes a complete set of Java EE 7 APIs
including a Bill of Materials (BOM). A BOM specifies
the versions of a "stack" (or a collection) of
artifacts. We use this here so that we always get
the correct versions of artifacts. -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom</artifactId>
<version>${version.wildfly.swarm}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
現在你可以添加其他的JavaEE
元件(或者你可以進行使用自己的依賴,讓WildFly Swarm自己偵測依賴),接下來讓我們看看jboss-forge
如何構建工程。
筆者嚐試將
hola-backend
按照如上方式改成WildFly Swarm,但是結果並不如意
嚐試改造已有的web工程,結果也不好,可以看到這種方式隻是一種點綴
使用JBoss Forge
jboss-forge
是一個構建java項目的IDE插件和基於命令行的工具集,能夠在Netbeans、Eclipse和IDEA中提供這些功能,幫助開發人員創建java項目、添加CDI beans,或者配置servlets。首先運行環境需要使用JDK/Java 1.8,在這個基礎上進行安裝 JBoss Forge。
一旦你安裝了jboss-forge
,你可以在命令行下通過鍵入:forge
,啟動它。
在mac下使用Homebrew可以安裝它,運行:brew install jboss-forge就可以了
你可以使用Tab
鍵來獲得提示並讓命令自動完成,jboss-forge
是一個基於模塊化插件體係構建的工具,它支持其他用戶對插件體係將進行擴展,你可以在這裏找到擴展的插件addons contributed by the community,有很多插件可以選擇,比如:AsciiDoctor
、Twitter
、Arquillian
以及AssertJ
,我們先用jboss-forge
安裝WildFly Swarm。
[temp]$ addon-install --coordinate org.jboss.forge.addon:wildfly-swarm,1.0.0.Beta2
SUCCESS Addon org.jboss.forge.addon:wildfly-swarm,1.0.0.Beta2 was installed successfully.
筆者查看了WildFly Swarm文檔,推薦這麼安裝最新版:addon-install-from-git --url https://github.com/forge/wildfly-swarm-addon.git --coordinate org.jboss.forge.addon:wildfly-swarm
進入jboss-forge
後,可以使用project-new
來進行項目的創建。接下來我們創建一個WildFly Swarm項目:hola-wildflyswarm
,並且為這個應用添加REST以及WildFly Swarm的支持。
可以通過
wildfly-swarm-run
來啟動項目,但是退出項目遇到點小問題
我們將工程導入到IDE中,可以看到一個應用的骨架,如果我們打開pom.xml
,會看到相關的JavaEE
APIs以及WildFly Swarm插件。
<build>
<finalName>hola-wildflyswarm</finalName>
<plugins>
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<version>${version.wildfly-swarm}</version>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.wildfly-swarm>2017.6.1</version.wildfly-swarm>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>3.0.3.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom-all</artifactId>
<version>${version.wildfly-swarm}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
記住,WildFly Swarm隻會打包你需要的JavaEE
框架,在這個例子中,我們首先添加了JAX-RS(rest-setup
),所以WildFly Swarm會自動包含JAX-RS以及servlet元件,並將它們打包到你的應用中。
在WildFly Swarm中,有三個類型的類加載器,首先是啟動它的SystemClassLoader,第二個是應用的類加載器,也就是用來執行用戶代碼的地方,最後一個是WildFly,有理由相信,WildFly Swarm利用了JBoss模塊化技術,而這個技術的運用,使得應用代碼隻需要依賴標準的API,而具體的
JavaEE
實現和自己已經隔離開來
添加HTTP端點
現在在jboss-forge
下,使用rest-new-endpoint
添加一個JAX-RS端點。
進入到
hola-wildflyswarm
目錄下,執行forge
在IDE中,可以看到已經創建了一個類HolaResource
:
@Path("/api/holaV1")
public class HolaResource {
@GET
@Produces("text/plain")
public Response doGet() {
return Response.ok("method doGet invoked").build();
}
}
我們可以通過在jboss-forge
中運行wildfly-swarm-run
將應用啟動起來,打開瀏覽器訪問:https://localhost:8080/api/holaV1
,會看到如下頁麵。
是不是很快,我們做了些什麼?我們使用jboss-forge
構建了一個JAX-RS的web應用,它使用原生的JavaEE
技術,能夠以微服務的形式運行。
外部配置
本文編寫的時候,WildFly Swarm還沒有一種方式進行外部配置,也沒有一套配置框架,例如:Apache Commons Configuration或者Apache DeltaSpike Configuration組件。如果想要使用WildFly Swarm自己提供的配置功能,可以關注this JIRA thread。在本章中,將使用Apache DeltaSpike Configuration來完成配置。
翻譯本文時,WildFly Swarm配置已經可以使用,訪問這裏:Swarm Config
Apache DeltaSpike Configuration是一個2014年的Duke選擇獎獲得者,也非常不錯
Apache DeltaSpike Configuration是一個CDI擴展的集合,用來簡化諸如:配置、數據獲取以及安全等方麵,接下來就需要使用CDI擴展來將配置注入到代碼中,而配置的來源能夠是命令行、屬性文件、JNDI或者環境變量。首先添加CDI的依賴。
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs-cdi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.core</groupId>
<artifactId>deltaspike-core-api</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.core</groupId>
<artifactId>deltaspike-core-impl</artifactId>
<version>1.5.3</version>
</dependency>
由於使用了Apache DeltaSpike Configuration,使用它需要創建META-INF/apache-deltaspike.properties
,在這個配置中放置我們需要的配置。
這樣針對變量WF_SWARM_SAYING
,就可以注入這個值了,下麵創建HolaResource2
。
@Path("/api/holaV2")
public class HolaResource2 {
@Inject
@ConfigProperty(name = "WF_SWARM_SAYING", defaultValue = "Hola")
private String saying;
@GET
@Produces("text/plain")
public Response doGet() {
return Response.ok(saying + " from WF Swarm").build();
}
}
可以看到如果沒有WF_SWARM_SAYING
配置,將會默認使用Hola,接著我們打包運行。
$ mvn clean package
$ java -jar target/hola-wildflyswarm-swarm.jar
打開瀏覽器,訪問:https://localhost:8080/api/holaV2
,可以看到以下內容。
我們停止應用,然後導出一個環境變量,然後再啟動應用。
$ export WF_SWARM_SAYING=Yo
$ java -jar target/hola-wildflyswarm-swarm.jar
打開瀏覽器,再次訪問:https://localhost:8080/api/holaV2
,可以看到內容已經變化。
暴露應用Metrics和信息
暴露應用的Metrics十分簡單,隻需要添加一個依賴一個maven坐標即可,添加坐標:
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>monitor</artifactId>
</dependency>
它將啟動WildFly管理以及監控功能,從監控的角度看,WildFly Swarm暴露了一些基本的Metrics:
- /node
當前部署節點的信息 - /heap
堆信息 - /threads
Java的線程信息
當然也可以自定義添加一些端點用於檢查微服務是否運作正常,你可以檢測集群中哪台機器上的微服務是否工作正常,如果想了解詳細的信息可以查看WildFly Swarm documentation。
調用其他服務
在微服務環境下,服務之間是會進行相互調用的,如果我們想使用之前的服務,就需要使用JAX-RS客戶端,就像之前在Spring Boot微服務下調用books接口一樣。
接下來創建一個類型GreeterResource
,使用JAX-RS客戶端訪問hola-backend
,由於使用了JAX-RS,所以與hola-dropwizard
的代碼有些類似。
@Path("/api")
public class GreeterResource {
@Inject
@ConfigProperty(name = "GREETING_BACKEND_SERVICE_HOST",
defaultValue = "localhost")
private String backendServiceHost;
@Inject
@ConfigProperty(name = "GREETING_BACKEND_SERVICE_PORT",
defaultValue = "8080")
private int backendServicePort;
@Path("/greeting/{bookId}")
@GET
public String greeting(@PathParam("bookId") Long bookId) {
String backendServiceUrl = String.format("https://%s:%d",
backendServiceHost, backendServicePort);
System.out.println("Sending to: " + backendServiceUrl);
Client client = ClientBuilder.newClient();
Map map = client.target(backendServiceUrl).path("hola-backend").path("rest").path("books").path(
bookId.toString()).request().accept("application/json").get(Map.class);
return map.toString();
}
}
在hola-wildflyswarm
目錄下,執行mvn clean package
,完成應用的打包。在運行應用前,需要指定hola-backend
服務端的位置,我們可以通過環境變量指定。
$ export GREETING_BACKEND_SERVICE_HOST="11.239.175.192"
$ java -jar target/hola-wildflyswarm-swarm.jar
打開瀏覽器訪問:https://localhost:8080/api/greeting/1
,可以看到如下展示。
小結
通過本章內容,介紹了WildFly Swarm的基本使用方式,以及同Dropwizard和Spring Boot的對比,了解到如何暴露REST端點、配置、Metrics以及調用外部服務。快速的介紹WildFly Swarm不能麵麵俱到,下麵是深入了解它的一些資源。
由於使用了jboss-module模塊化係統啟動應用,WildFly Swarm啟動的速度慢於Spring Boot和Dropwizard,但是其隔離的體現,使得應用的jar包非常簡單,舊有的
JavaEE
遷移會有優勢,官方更新速度很快,但是小問題也很多
- WildFly Swarm
- WildFly Swarm documentation
- WildFly Swarm examples on GitHub
- WildFly Swarm Core examples on GitHub
- WildFly Swarm blog
- WildFly Swarm Community
最後更新:2017-11-03 15:05:15