Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 使用AOP開發android 遠程調用SDK

使用AOP開發android 遠程調用SDK

編輯:關於Android編程

“什麼是spring aop?”,我頓時大腦浮想聯翩,我想到了事物管理、SDK、代碼監控、spring remoting,這麼多東西,我從哪裡回答呢,後來變得大腦一片空白,這提問有問題啊,aop在我腦子裡面有那麼多表現形式,你如果提出一個功能,問我怎麼做,我肯定不會思維混亂的,本來aop就夠抽象了,你還問的這麼抽象。

“你用過aop嗎“

用過,我在給android的服務端接口SDK裡面用過的。android在調用服務端api的時候要對本地方法進行攔截,並且把最終實現邏輯加上http調用的代碼...。

這跟aop有什麼關系?

好吧,沒什麼關系。但明白人說呢,到底有沒有關系?

下面我來解釋一下看看,大家給評評理。

這次我先說一下android遠程api調用SDK的實現方式。

\

舉例,修改密碼的功能。在沒有sdk之前一般都這麼寫的

 

User user = new User();
user.setPassword(password);
HttpClient client = new HttpClient();
client.remoteUrl = “http://a.com/user/modifyPassword”
client.params = JSON.toJsonString(user);
String response = client.invokeUrl();
ServiceInvokeResult result = JSON.parse(response ,ServiceInvokeResult .class);
If(result.status == ‘200’ && result.resultMessage == ‘success’){
System.out.println(‘修改成功’);
}

 

這麼寫沒啥不行的,但我認為有幾個問題:

1.第2、3、4、5、6行的代碼,在涉及到其他的服務端接口調用的地方都需要寫的。

2.Android程序員必須知道remoteUrl怎麼寫,實際上他並不關心這玩意的

3.Android需要處理參數、返回值序列化

實際上上面幾個問題可以歸納為:android程序員想少些代碼。

那麼代碼能否改成這樣呢

 

User user = new User();
user.setPassword(password);
InvokeResult result = userService.modifyPassword();

 

看起來像是調用一個本地的方法,而且這樣至少能少寫4行代碼吧,可能有些人會說:這算個鳥,我們開發程序最主要的目的是快速完成任務,有那時間復制粘貼早搞定了,思考那麼多浪費時間。

如果你是這種思想的話,那就看到這裡為止吧。下面的內容不是給你看的,有興趣的可以往下面看。

有人說把少寫的那些代碼放到modifyPassword()裡面不就完了嗎,呵呵。我會說,“dont’t give me your suit,you know i mean that”.

怎麼寫才能讓調用本地方法擁有調用遠程服務的能力。我們實際上是在修改方法的實現邏輯

仔細觀察每一個包含遠程調用的實現代碼,我們可以發現,這類代碼都有包含下面的邏輯

\

進一步講,我們應該把組裝參數,發起http請求和獲取請求的返回值提取到一個公共的地方,並且讓每一個實現代碼自動去調用,如何實現這個自動。

我們都聽說過AOP,那再去看看這篇文檔http://shouce.jb51.net/spring/aop.html

看完後有我感覺沒有頓時豁然開朗的感覺,不能馬上感覺到與我們要解決的問題有什麼關系,而是睡著了,這是他媽誰寫的玩意,看了讓老子想睡覺。

我用我自己能理解的語言來解釋一下:AOP像是一個監視系統,他能監視你的代碼執行,並且根據你的需求在你代碼執行之前、執行之後、拋異常的時候做出反應,他的核心是代理,最終運行的是代理類,而不是你自己寫的類。

你的代碼把組裝參數發起http請求、獲取請求的返回值代理給代理類處理

\

AOP代理分為靜態代理和動態代理,靜態代理指的是在編譯期生成代理類,一般用命令生成,像AspectJ,它的邏輯是用它的命令修改了生成的class,你可以把class用反編譯工具打開查看,裡面有很多它生成的代碼。而動態代理是在運行時在內存中生成代理類。

不像服務端程序,你想引入什麼類庫就引入什麼類庫,在android這種環境中,盡量不要引入第三方類庫,因為那是要打包進去的,增加apk的體積。接下來,我們用jdk自帶的動態代理來實現。

Java創建代理類是通過java.lang.reflect.Proxy的newProxyInstance方法來完成的,這個方法有三個參數

ClassLoader loader:代理類的類加載器

Classinterfaces: 代理類要實現的接口,最終會產生一個代理類名字是 $ProxyN(N=1-65535),這個代理類要實現這些接口

InvocationHandler h:實現了InvocationHandler接口的類

這裡面有一些要求:

1.要代理的類必須用接口的形式。

為啥?

規范呗,java不是一直在說面向接口編程嗎。

那我告訴你CGLIB沒這個要求。

啥B,那就是那啥B不規范呗...

我來告訴你吧,newProxyInstance生成的代理類都繼承了Proxy,java又不允許多繼承,但是可以多實現。

哦,明白了,只能繼承一個,那我先把這個坑占了。那我明白了又能怎樣,你告訴我,我明白了這玩意能漲工資不?

......

2.你需要提供一個實現了InvocationHandler 的類,在這個類裡面做你的邏輯,比如把組裝參數,發起http請求和獲取請求的返回值等相關代碼放進去。

 

那就動手寫起來呗,我們先來寫一個InvocationHandler 實現類,這個類是抽象的,因為有可能有多種用途的實現類,代碼看起來像下面的樣子

 

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
 
 
public abstract class ProxyFactory implements InvocationHandler {
 
    private Class targetClass;
 
    private String targetClassName;
 
    private String methodName;
 
    public String getTargetClassName() {
        return targetClassName;
    }
 
    public String getMethodName() {
        return methodName;
    }
 
 
    public ProxyFactory(Class clazz){
        super();
        this.targetClass = clazz;
    }
    public M getProxy(){
        return (M) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class[]{targetClass}, this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            //獲取方法名
            this.methodName = method.getName();
            //獲取參數名
            String[] argNames = Classes.parseMethodVarNames(method);
            before(argNames, args);
            this.targetClassName = targetClass.getName();
            result = after(method.getGenericReturnType());
 
        } catch (Exception e) {
            onException(e);
        }
        return result;
    }
    public abstract void onException(Exception ex);
 
    public abstract Object after(Type type);
 
    public abstract void before(String[] argNames,Object[] args);
}

 

InvocationHandler 只有一個方法invoke,在這裡面傳入,代理類,代理類的方法,方法的參數值。

我們另外定義3個方法以備後用,分別代表before(方法調用之前邏輯)、after(方法調用後邏輯),onException(方法拋異常邏輯)。

我們再定義一個用來做遠程調用的實現類,如下

 

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
 
public class RemoteProxy extends ProxyFactory {
 
    private HTTPClient client = new HTTPClient();
 
    private Map map = new HashMap();
 
    public RemoteProxy putOtherParameters(String parameterName,Object parameterValue){
        map.put(parameterName,parameterValue);
        return this;
    }
 
    public RemoteProxy(Class clazz){
        super(clazz);
    }
    @Override
    public void onException(Exception ex){
        ex.printStackTrace();
    }
 
    @Override
    public Object after(Type returnType) {
        String serviceUri = Classes.parseClassMethodToUri(super.getTargetClassName(), super.getMethodName());
        client.setServiceUri(serviceUri);
        String responseStr = client.request();
        return Classes.stringToObject(responseStr,returnType);
    }
 
    @Override
    public void before(String[] argNames, Object[] args) {
        map.clear();
        for(int i = 0;i < argNames.length;i ++){
            String argName = argNames[i];
            map.put(argName,args[i]);
        }
        client.setParams(map);
    }
}

 

在before的實現裡面,我們組裝參數。在after中我們設置調用的服務端url,進行遠程調用,接著反序列化服務端的返回值。

假設你要代理UserService的接口,那麼我們通過下面的代碼去創建一個UserService的代理對象,並且調用相關業務方法

 

UserService userService = new RemoteProxy(UserService.class).getProxy();
userService.modifyPassword();

 

網上說AOP是面向方面、切面編程,那麼我們通過上面的例子可以看出before、onException、after就是AOP提供給我們的方面、切面的某種表現形式,明白了嘛?

沒明白!

......

那我抽時間再弄點別的例子吧。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved