並不是全部人都認爲Java 編程語言很性感。可是,從最保守的企業到最古怪的初創企業,Java 虛擬機都是無處不在的主導力量。現在,有許多可替代的語言可編譯爲Java字節碼。有基於JVM的Python,Ruby版本和JavaScript的多種實現。有全新的語言,例如 JetBrains的Kotlin和RedHat的Ceylon。Clojure最近從新喚起了對Lisp和Scala的興趣很大程度上是2000年服務器端向功能編程的轉變的緣由。java
Groovy是全部人的祖父,今天幾乎無處不在。當它在13年前首次出現時,Groovy馬上受到歡迎。該語言和相關的Grails Web框架將Ruby on Rails的新興流行與Java開發人員的極淺學習曲線結合在一塊兒。在幾乎一晚上之間,Groovy徹底取代了之前的JVM腳本替代品BeanShell。mysql
對Rails模型的熱情最終減弱了,強類型的語言再次成爲趨勢。坦率地說,許多僅僅由於它是「新的」而蜂擁至Groovy的人仍在繼續開發新事物。可是,Groovy並無消失。相反,它已經成爲「企業時髦」語言的成熟角色。隨處可見。JVM上幾乎全部公開腳本接口的應用程序都以Groovy爲頭等公民而這樣作。Groovy是與QA很是流行的自動化測試空間,被深深植入到Spring框架,而且是快速增加的基礎搖籃構建系統。sql
咱們沒有像之前那樣大肆宣傳Groovy,可是它在Java生態系統中已經根深蒂固,而且還在不斷擴展。這是一個穩定,安全的選擇,爲此,很容易找到人才(或快速在職培訓)。儘管今天有更多時髦的流行語要放在您的簡歷上,可是Groovy很快就消失out盡的風險彷佛很小。Groovy「行之有效」,是每一個Java開發人員都應該在其工具箱中使用的很是方便的工具。數據庫
除了歷史,讓咱們談論一個最近的用例,它使我沒法使用Groovy技能。我須要爲在多種環境中運行的許多應用程序快速創建一個「鍵值」配置參數註冊表。我想在源代碼管理中將這些參數捕獲爲屬性文件的集合。每一個應用程序一個文件,嵌套在每一個環境的子目錄中:編程
…
qa-env/
application-a.properties
application-b.properties
…
staging-env/
application-a.properties
application-b.properties
…複製代碼
每當在源代碼管理中提交對這些屬性文件的更改時,我都但願Jenkins(或其餘連續集成服務器)將其值與運行時「註冊表」同步。該註冊表最終可能會變成etcd或Consul和Vault之類的東西,可是咱們可使用傳統的MySQL數據庫快速開始工做。安全
因爲這些天咱們的大多數持續集成構建做業都是基於Gradle的,而且因爲Gradle是Groovy本機的,所以咱們能夠將這種「同步」做業烘焙到Gradle構建中。經過基於JavaExec的任務(指向Groovy腳本),您能夠將Gradle用做Groovy應用服務器!服務器
apply plugin: 'groovy'
repositories {
mavenCentral()
mavenLocal()
}
// [1] Declare a localGroovy() dependency, to use
// the Groovy library that ships with Gradle.
dependencies {
compile localGroovy()
compile("mysql:mysql-connector-java:5.1.35")
compile("com.h2database:h2:1.4.187")
testCompile("junit:junit:4.12")
}
// [2] Create a task of type 'JavaExec', referencing
// a Groovy script and any input arguments.
task runScript(type: JavaExec) {
description 'Run a Groovy script to sync the environment config registry with the properties files in source control'
classpath = sourceSets.main.runtimeClasspath
main 'com.mypackage.SyncScript'
args Arrays.asList('jdbc:mysql://registry/db', 'com.mysql.jdbc.Driver', 'user', 'password').toArray()
}
// [3] Tell Gradle to invoke your Groovy script task.
defaultTasks 'runScript'複製代碼
編寫執行某些任意Groovy代碼的Gradle構建腳本至關簡單。因爲現在運行Gradle的首選方法是經過精簡包裝器腳本,所以無需安裝Gradle,就能夠直接從源代碼控制存儲庫將此解決方案傳遞到任何地方。閉包
換句話說,只要提交了源代碼控制存儲庫,就可使 Jenkins運行Groovy腳本。併發
如今,對於真正整潔的部分,Groovy「同步」腳本自己。該腳本掃描任意數量的每一個環境目錄,掃描每一個目錄中的任意數量的每一個應用程序屬性文件,並將這些屬性與MySQL數據庫表同步。app
// Iterate through each per-environment directory
new File('config').eachDir { File environmentDirectory ->
// Iterate through each per-application properties file
environmentDirectory.eachFileMatch FileType.FILES, ~/.+\.properties/, { File applicationFile ->
def environment = environmentDirectory.name
def application = applicationFile.name.replace('.properties', '')
println "Processing properties for env: '$environment', application: '$application'"
// Parse the file into a java.util.Properties object
def properties = new Properties()
applicationFile.withInputStream { stream -> properties.load(stream) }
...
}
}複製代碼
Java 8 Streams使這種事情在純Java領域變得更加友好和易讀,可是它仍然沒法觸及Groovy對 File等類的擴展的簡單性 。該eachDir()和eachFileMatch()附加的方法能夠很容易地經過迭代全部的目錄,並掃描具備擴展名「properties「文件的。所述withInputStream()方法能夠幫助咱們加載每一個文件的內容到一個java.util.Properties與單行對象。
除了對java.io.File的擴展以外,Groovy還提供了本身的groovy.sql.Sql類來促進JDBC操做。這減小了構造數據庫查詢所需的許多樣板,並容許咱們在閉包內處理其ResultSet:
database = groovy.sql.Sql.newInstance(jdbcUrl, jdbcUsername, jdbcPassword, jdbcDriver)
database.resultSetConcurrency = ResultSet.CONCUR_UPDATABLE
// Iterate through the properties, and sync MySQL
properties.entrySet().each {
def name = it.key
def value = it.value
def existingRecordQuery = '''
SELECT environment, service, property_name, property_value FROM environment_properties
WHERE environment = ? AND service = ? AND property_name = ?
'''
database.query(existingRecordQuery, [environment, service, name]) { ResultSet rs ->
if (rs.next()) {
def existingValue = rs.getString('property_value')
if (existingValue.equals(value)) {
// Existing property value is unchanged. No-op.
} else {
// Existing property value has changed. Update.
rs.updateString('property_value', value)
rs.updateRow()
}
} else {
// New property. Insert.
rs.moveToInsertRow()
rs.updateString('environment', environment)
rs.updateString('service', service)
rs.updateString('property_name', name)
rs.updateString('property_value', value)
rs.insertRow()
}
}
}
// TODO: Remove from the database properties that have
// been removed from the properties file.複製代碼
這裏發生了一些有趣的事情:
這個特定的用例很是具體,可是它展現了多個概念,這些概念在隔離中普遍有用。Groovy是一種很是強大的語言,在沒有其餘替代方法的環境中可能會受到歡迎。它是Gradle的本機,後者已迅速成爲Java生態系統中最主要的構建工具,所以Groovy易於經過您的持續集成服務器加以利用。最後,Groovy提供了完整的類庫以及對核心Java類的擴展,這些真正地消除了許多常見任務的樣板和複雜性。