本篇是《使用Spring Boot和Docker構建微服務架構》系列的第三篇,本篇我們將會準備開始構建一個員工對象微服務。原文作者為3Pillar環球旗下美國Adbanced技術集團的總監Dan Greene,Dan有十八年的軟件設計和開發經驗,包括在電子商務、B2B集成、空間分析、SOA架構、大數據以及云計算等領域的軟件產品架構經驗,他是AWS認證解決方案架構師,在3Pillar之前先后就職于Oracle、ChoicePoint和Booz Allen Hamilton。Dan畢業于喬治·華盛頓大學,他也是一個父親、業余木工愛好者,還參加過包括國際障礙大賽這樣的障礙賽跑。本篇構建微服務的步驟如下:建立一個新的Spring Boot工程
定義我們的員工對象
持久連接
公開Web服務
定義一個Docker容器來運行我們的微服務,包括連接到我們在第二篇中創建的Mongo容器
在稍早設置的Docker Machine中運行我們的容器
建立我們的Spring Boot工程我們將在我們的工程根目錄下創建一個文件夾(生產環境中是在一個單獨的版本庫中)來承載我們的服務,在這個文件夾中,我們將創建build.grade文件。Spring Boot的優勢就是在于對于依賴定義非常純粹,如魔法般地帶來了大量的互操作性。我們的build.grade文件看起來如下:buildscript {repositories {jcenter()}dependencies { classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.2.0.RELEASE'}}apply plugin: 'spring-boot'repositories { jcenter()}dependencies {compile "org.springframework.boot:spring-boot-starter-actuator"compile "org.springframework.boot:spring-boot-starter-web"}
現在,正如我們提到的,我們將使用IDE,具體地說就是Spring Tool Suite(STS),所以我們將增加對于Gradle的支持。首先,打開STS,接著在打開的Dashboard頁面上點擊“IDE Extensions”的鏈接:
在屏幕上選擇“Grade Support”,點擊“Install”,按照提示完成安裝,其中包括重啟STS:
重啟之后,選擇“Import project…”,接著選擇Gradle project(現在可用了),指向你的目錄,然后點擊“Build Model”——這將會用“Employee”來產生項目列表——選擇這個列表并且點擊“Finish”,這將會導入一個簡單的build.grade到我們啟動的工程。一旦工程被導入之后,第一個將是Spring Boot配置類,在這個場景中,我們將按照他們的服務來命名,所以在這種情況下配置類將會命名為EmployeeBoot。Spring大量使用了注解和反射,所以最小的配置也是需要的(忽略導入):@Configuration@EnableAutoConfiguration@ComponentScanpublic class EmployeeBoot { public static void main(String[] args) { SpringApplication.run(EmployeeBoot.class); }}
我們的Employee類接下來,我們將使得我們的POJO類來持有員工信息,我們目前保持最少的字段,有必要的話我們將增加:Employee.Class@Document(collection=”employees”)public class Employee {@Idprivate String id; private String email;private String fullName;private String managerEmail;// getters and setters omitted for brevity}
注意@Document這個注解——這會將這個對象連結為一個Mongo文檔,并為該Employee“文檔”在哪里存儲指定了集合名字。接下來我們將定義一個Spring持久類來讀取這些Employee:EmployeeRepository.class:public interface EmployeeRepository extendsMongoRepository<Employee, String> {}
Spring框架的一個優美之處就是在于所有你需要寫的——比如擴展自MongoRepository的接口甚至不需要手動編寫實現代碼。兩個通用的參數中第一個表示需要持久化的對象類型(Employee),第二個表示唯一的標識符類型(String類型)。Spring框架將會自動提供所聲明的功能95%的實現。接下來的問題就是:Spring如何知道數據庫的位置?Spring默認情況下將會尋找localhost:27017,這顯然是不會工作的,所以我們需要直接設置位置新型。我們可以實現自己的Mongo模板Bean,但是幸運的是Spring允許我們通過Java屬性表傳遞連接信息。我們可以定義一個屬性文件或者在命令行上傳遞進來。我們選擇了后者因為當稍后構建我們的容器時命令行方式非常方便。最后我們需要創建的是一個或者兩個Rest端點并確保它們可以工作。我們將構建一個快速的Spring Controller,然后我們就可以測試了。EmployeeController.java@RestController@RequestMapping("/employee")public class EmployeeController {@AutowiredEmployeeRepository employeeRepository;@RequestMapping(method = RequestMethod.POST)public Employee create(@RequestBody Employee employee){ Employee result = employeeRepository.save(employee); return result;}@RequestMapping(method = RequestMethod.GET, value="/{employeeId}")public Employee get(@PathVariable String employeeId){ return employeeRepository.findOne(employeeId);}}
最開始的@RestController和@RequestMapping這兩個類級別的注解告訴Spring框架需要公開這是一個接收JSON的Rest服務,并且公開了URI路徑是/employee。@Autowired注解告訴Spring框架采用上面我們定義的Repository接口的自動生成實現代碼并將其注入到這個Controller中。現在到了特定的操作——方法級別的@RequestMapping注解表明這個方法將會基于HTTP動詞來使用(在本例中是POST和GET),另外對于GET操作,我們指明了一個URL路徑{employee},比如使用/employee/abcd1234來尋找一個員工并且返回該值。現在我們有了足夠多的準備工作可以來測試了,第一點,我們需要編譯和運行我們的Spring Boot應用,在Eclipse中有很多方法可以做到這一點,但是我們將從命令行開始,并以我們的方式工作。在你的Employee目錄中,敲入:gradle build
,這個命令將會編譯Spring Boot應用到build/lib/Employee.jar,這個jar包包含了運行這個應用所需要的所有東西,包括一個嵌入式的Servlet容器(默認情況下是Tomcat)。在我們運行和測試這個應用之前,我們需要稍作回顧——我們的Mongo服務又在哪里?觀察“docker ps”命令的輸出,我們記得虛擬機的32777端口映射到了Mongo容器的27017端口,虛擬機的IP地址是192.126.99.100。如前所述,我們可以通過傳遞一個環境變量屬性的方式來把連接屬性傳遞給Spring,所以運行這個應用的命令行如下:java -Dspring.data.mongodb.uri=mongodb://192.168.99.100:32777/micros -jar build/libs/Employee.jar
一旦應用啟動之后(應該在1~4秒),你可以使用選項中的Rest工具來打開Web服務。
不要忘了在HTTP頭部包含值為“application/json”的“Content-Type”,你應該收到如下的響應(id的值取決于你自己的情況):{"id": "55fb2f1930e07c6c844b02ff","email": "dan.greene@3pillarglobal.com","fullName": "Daniel Greene","managerEmail": null}
你可以通過如下的調用測試我們的GET方法:http://localhost:8080/employee/55fb2f1930e07c6c844b02ff
你應該得到相同的文檔,萬歲!我們的服務起作用了!將Boot應用導入容器現在我們需要構建我們的第一個容器來運行我們的Employee微服務。我們的途徑是定義一個Dockerfile,這個文件將會定義如何生成一個鏡像并放入我們的精益求精、短小精悍的微服務中。讓我們閱讀這個文件并逐步解析(參考第三篇第三步請跳到這兒):FROM java:8VOLUME /tmpADD build/libs/Employee.jar app.jarEXPOSE 8080RUN bash -c 'touch /app.jar'ENTRYPOINT ["java","-Dspring.data.mongodb.uri=mongodb://mongodb/micros", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
我們從一個包含了安裝了Java 8的標準鏡像(鏡像名字為“Java”,標簽為“8”)開始構建過程
我們接著定義了一個名為/tmp的卷
接著將本地文件系統的一個文件添加進來,并且重命名為“app.jar”,重命名不是必須的,只是一個可用的可選項
我們聲明想要公開容器的8080端口
在容器內運行一個touch命令,這樣可以確保app.jar文件的修改日期
ENTRYPOINT命令定義了容器啟動時需要運行的內容——我們運行Java,設置我們的Spring Mongo屬性,還有快速的附加屬性來加速Tomcat啟動時間,然后指向我們的jar包。
現在我們通過運行如下命令構建鏡像:docker build -t microservicedemo/employee .
我們可以敲入docker images
看到結果REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEmicroservicedemo/employee latest 364ffd8162b9 15 minutes ago 846.6 MB
接下來的問題就是“我們的服務容器如何與Mongo容器交互?”,為此,我們引入了容器的link機制。當你運行一個新的容器時,你可以傳入一個可選的-link參數指定一個運行中的容器的名字,這樣新的容器就可以與這個容器通訊了,所以我們的命令是:docker run -P -d --name employee --link mongodb microservicedemo/employee
我們啟動了一個新的容器,公開了端口(-P),以后臺方式運行(-d),命名為employee(—name),接著將這個新的容器連接到了一個名為“mongodb”的容器(-link),連接過程如下:在employee容器的host文件添加一個條目指向MongoDB容器的運行位置
在employee容器內添加一些環境變量來協助其他必要的編程訪問,可以運行如下命令查看: {{{docker exec employee bash -c 'env | grep MONGODB'}}}
允許容器通過公開的端口來直接通訊,這樣就不需要擔心主機的部分映射了。如果你還記得上述的內容,我們設置了Spring Mongo到MongoDB的URL作為主機名(mongodb://mongodb/micros),所以有了host文件條目和運行在默認端口的Mongo,Boot應用容器可以連上數據庫了
在容器運行時我們可以來執行相同的Web服務,只是這次是作為容器來運行的(對于我來說,容器的8080端口會被映射到虛擬機的32772端口):
本篇我們已經取得了很大的進展,我們有了兩個容器可以工作并且可以互相通訊,接下來的第四篇我們將添加一些額外的服務/容器,可以觀察到構建更新的進度并與CI工具集成工作。原文鏈接:BUILDING A MICROSERVICE ARCHITECTURE WITH SPRING BOOT AND DOCKER, PART