SCM - 組件化通信工具
一切皆組件,當(dāng)每個(gè)組件可看成一個(gè)微服務(wù)及舍,組件化項(xiàng)目才會(huì)真正解耦
組件化介紹:
通過一個(gè)類比的例子來介紹組件化
隨著業(yè)務(wù)的復(fù)雜度增大未辆,業(yè)務(wù)線縱橫交錯(cuò),往往牽一發(fā)而動(dòng)全身锯玛。
我們希望業(yè)務(wù)代碼也能像一部智能手機(jī)咐柜。
入口模塊:應(yīng)用桌面圖標(biāo),更像是home模塊攘残,只提供入口拙友;
業(yè)務(wù)模塊:通過appstore,下載我們需要的app歼郭,每個(gè)app(模塊)職責(zé)分明遗契,鬧鐘,短信病曾,電話......牍蜂;
當(dāng)某個(gè)模塊需求變化,并不想影響到其他業(yè)務(wù)線的大規(guī)模變動(dòng),只用更新當(dāng)前app(模塊)泰涂;
甚至 -- 我的模塊鲫竞、組件可以發(fā)到 appstore 給其他手機(jī)使用(插件化),每個(gè)應(yīng)用可以資源互動(dòng)(組件通信)负敏,可以增量更新…
所以:
一切皆組件贡茅,
每個(gè)模塊就是一個(gè)微服務(wù),通過 rest api 來訪問其做,用完即走顶考。
SCM介紹:
SCM就是用來定義api接口(通過注解在編譯期生成服務(wù)注冊(cè)表),通過請(qǐng)求(SCM.req)妖泄,來拿到對(duì)應(yīng)服務(wù)(action)的響應(yīng)結(jié)果(ScCallback)的工具
SCM 不支持 Install Run
1: 通過注解注冊(cè) @Action(name = "") 聲明服務(wù) 類實(shí)現(xiàn)ScAction
2: 一個(gè) Action 對(duì)應(yīng)一個(gè)微服務(wù)
3: 通過對(duì)注解 Compiler 編譯期生成 -> 服務(wù)注冊(cè)表
4: Application 初始化 運(yùn)行期掃描服務(wù)驹沿、緩存注冊(cè)表
5: 調(diào)用 SCM.req(String action,Callback A) 調(diào)用服務(wù), 真正實(shí)現(xiàn)解耦
action ---> module actionTable ---> scmTable
使用:
1:根項(xiàng)目root-project的build.gradle
repositories {
...
maven {
url "https://dl.bintray.com/woaigmz/SCM"
}
}
2:你的每個(gè)module的build.gradle
dependencies {
compile 'com.woaigmz.scm:scm-api:0.0.5'
compile 'com.woaigmz.scm:scm-annotation:0.0.5'
annotationProcessor 'com.woaigmz.scm:scm-compiler:0.0.5'
}
3:初始化
@Modules(names = {"Main", "Home"})
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
SCM.get().scanningSCMTable(App.class);
}
}
4:定義 Service(@Action)為 module-home/actions/HomeLoadConfigAction,為 home-module 提供給外界的api
//home-module/actions/HomeLoadConfigAction
@Action(name = "LoadConfig", module = "Home")
public class HomeLoadConfigAction implements ScAction {
@Override
public void invoke(Context context, String param, ScCallback callback) {
//模擬加載網(wǎng)絡(luò)數(shù)據(jù)
DataProvider.getConfig(callback);
}
}
//home-module/actions/HomeEntryAction
@Action(name = "HomeEntry", module = "Home")
public class HomeEntryAction implements ScAction {
@Override
public void invoke(Context context, String param, ScCallback callback) {
Intent intent = new Intent();
intent.setClass(context, HomeActivity.class);
context.startActivity(intent);
callback.onCallback(true, "HomeEntryAction:我把HomeActivity打開了", "");
}
}
//除頁面跳轉(zhuǎn)之外蹈胡,大部分都是異步渊季,業(yè)務(wù)情景不同朋蔫,本框架不提供異步轉(zhuǎn)同步,開發(fā)者自己實(shí)現(xiàn)
5:請(qǐng)求:由action-name通過 SCM.req()方法在module-app / MainActivity 獲取 module-home/actions 下的服務(wù)action
private WeakHandler h = new WeakHandler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
String s = (String) msg.obj;
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
tvLoadConfig.setText(s);
return false;
}
});
//通過Action :"LoadConfig"請(qǐng)求; 響應(yīng):ScCallback 返回的是子線程進(jìn)行的網(wǎng)絡(luò)請(qǐng)求結(jié)果要用handler
private void loadConfigByHomeModule() {
try {
SCM.get().req(MainActivity.this, "LoadConfig", new ScCallback() {
@Override
public void onCallback(boolean b, String data, String tag) {
if (b) {
Message obtain = Message.obtain();
obtain.obj = data;
if (h != null) {
h.sendMessage(obtain);
} else {
Toast.makeText(MainActivity.this, "WeakHandler has been Gc", Toast.LENGTH_SHORT).show();
}
}
}
});
} catch (Exception e) {
Log.e(Constants.SCM, e.getMessage());
}
}
//跳轉(zhuǎn)到 Home-module/view/HomeActivity
try {
SCM.get().req(MainActivity.this, "HomeEntry", new ScCallback() {
@Override
public void onCallback(boolean b, final String data, String tag) {
if (b)
Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
Log.e(Constants.SCM, e.getMessage());
}
想法:
想到 java 后臺(tái)通過action來定義一個(gè)接口 却汉,servlet里的 req驯妄,res,有更好的歡迎issue合砂,star fork 青扔。。翩伪。
具體實(shí)現(xiàn)思路可用參考項(xiàng)目:SCM地址:
注解工具的作用:action 加到注冊(cè)表微猖,通過 annotationProcessor 編譯時(shí)注解,編譯期生成(SCMTable)表注冊(cè)
注解工具鏈接:ActionProcessor.java
SCM優(yōu)點(diǎn):
1:跨進(jìn)程缘屹,通過傳遞的 json/string 字符實(shí)現(xiàn)類似 CC 的通過socket協(xié)議傳遞字符流
2:通過action對(duì)應(yīng)的name凛剥,反射調(diào)用Action的invoke方法,實(shí)現(xiàn)解耦合 類似組件化項(xiàng)目 ModularizationArchitecture (aidl + service跨進(jìn)程)
3:注冊(cè)表簡潔易懂轻姿,想到了R文件的生成犁珠,public static final "$actionName" = "@action對(duì)應(yīng)action的實(shí)際包名"
4:只要原來的協(xié)議不變(@action(name="XXX"))代碼重構(gòu)不會(huì)對(duì)action有影響
5:編譯期生成SCMTable提高了掃描整個(gè)包的性能
maven上傳命令:
gradle install / gradlew bintrayUpload 上傳項(xiàng)目到 maven
查看有焦點(diǎn)的activity的包名
linux:adb shell dumpsys activity | grep "mFocusedActivity" / windows:adb shell dumpsys activity | findstr "mFocusedActivity"
不提供異步轉(zhuǎn)通過方法,因?yàn)槌隧撁嫣D(zhuǎn)踢代,一般的action都是耗時(shí)操作盲憎,處理方式留給開發(fā)者具體問題具體對(duì)待嗅骄,
幾種異步轉(zhuǎn)同步:
wait / notify
條件鎖
Future
CountDownLatch/CyclicBarrier
Handler
信號(hào)量