TAC是一個基於java的微服務容器,提供從業務代碼編寫、編譯、發佈、jar動態加載、運行等一系列經常使用開發流程的支持,是天貓App在服務端開發模式下的新嘗試。TAC和客戶端框架Tangram結合,極大提升開發效率;TAC目前在天貓App、手機淘寶特價版普遍使用;java
天貓App(如下簡稱貓客)首頁從2015年的坑位運營走向2016年的全面個性化,當時貓客首頁的個性化業務多大50多處。以首頁爲例,這個過程當中除了接入導購鏈路的二方服務以外,接入了大量的三方服務;同時咱們發現:android
當時微服務的概念已經很火,同時阿里內部也開始大力推廣docker(如今大部分應用都跑在docker上)。咱們想過將龐大的首頁應用拆分紅微服務,可是和基礎服務不一樣,前臺業務變化快,修改頻繁,拆分以後開發同窗依然要面臨各類服務接入等體力勞動,同時須要維護拆分以後的多個應用,反而增長了勞動成本,所以拆分紅微服務的方式治標不治本;ios
在此背景下TAC孕育而生,它提供低成本開發與發佈流程、低成本搭建與維護開發環境、高穩定性保障;TAC經過熱部署的方式使得研發同窗夠從苦力勞動中解放出來,迴歸到業務開發中去,同時一個基礎服務接入以後,可以提供給多個業務使用;在此模式下,業務可以進行更細粒度的拆分,且故障隔離業務A的改動不會影響業務B;git
在TAC的幫助下,頻繁修改的新業務可快速上線,不會出現由於修改一個字段、幾行代碼就須要從新發布整個應用的狀況;同時與tangram結合,實現頁面卡片、坑位的快速調整;github
通過近三年的沉澱,咱們今日放出了開源版本,將集團版本的TAC剝離與阿里相關的中間件、網絡、協議、部署環境等,保留其核心功能;開源版本提供了編譯、熱加載、運行的基礎能力;redis
上圖是tac的類加載器結構,每一個線上的微服務實例都經過一個新的classloader加載,同時爲了方便用戶擴展新的數據源,在AppClassLoader上擴展了一個classloader以加載第三方數據源(固然也能夠直接在代碼中擴展,見tac-infrastructure);docker
java -jar tac-container.jar
複製代碼
java -jar tac-console.jar --admin
複製代碼
http://localhost:7001/#/tacMs/list
複製代碼
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>tac-sdk</artifactId>
<version>${project.version}</version>
</dependency>
複製代碼
public class HelloWorldTac implements TacHandler<Object> {
/**
* 引入日誌服務
*/
private TacLogger tacLogger = TacServiceFactory.getLogger();
/**
* 編寫一個實現TacHandler接口的類
*
* @param context
* @return
* @throws Exception
*/
@Override
public TacResult<Object> execute(Context context) throws Exception {
// 執行邏輯
tacLogger.info("Hello World");
Map<String, Object> data = new HashMap<>();
data.put("name", "hellotac");
data.put("platform", "iPhone");
data.put("clientVersion", "7.0.2");
data.put("userName", "tac-userName");
return TacResult.newResult(data);
}
}
複製代碼
本地編譯、打包json
發佈及測試api
正式發佈bash
線上驗證
curl http://localhost:8001/api/tac/execute/helloworld -s|json
複製代碼
{
"success": true,
"msgCode": null,
"msgInfo": null,
"data": {
"helloworld": {
"data": {
"name": "hellotac",
"clientVersion": "7.0.2",
"userName": "tac-userName",
"platform": "iPhone"
},
"success": true,
"msCode": "helloworld"
}
},
"hasMore": null,
"ip": "127.0.0.1"
}
複製代碼