使用AOP开发android 远程调用SDK

“什么是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.第23456行的代码,在涉及到其他的服务端接口调用的地方都需要写的。

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.ProxynewProxyInstance方法来完成的,这个方法有三个参数

ClassLoader loader:代理类的类加载器

Class<?> interfaces: 代理类要实现的接口,最终会产生一个代理类名字是 $ProxyN(N=1-65535),这个代理类要实现这些接口

InvocationHandler h:实现了InvocationHandler接口的类

这里面有一些要求:

1.要代理的类必须用接口的形式。

为啥?

规范呗,java不是一直在说面向接口编程吗。

那我告诉你CGLIB没这个要求。

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

我来告诉你吧,newProxyInstance生成的代理类都继承了Proxyjava又不允许多继承,但是可以多实现。

哦,明白了,只能继承一个,那我先把这个坑占了。那我明白了又能怎样,你告诉我,我明白了这玩意能涨工资不?

......

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<M> implements InvocationHandler {
 
    private Class<M> 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<M> extends ProxyFactory<M> {
 
    private HTTPClient client = new HTTPClient();
 
    private Map<String,Object> map = new HashMap<String, Object>();
 
    public RemoteProxy<M> 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>(UserService.class).getProxy();
userService.modifyPassword();

网上说AOP是面向方面、切面编程,那么我们通过上面的例子可以看出beforeonExceptionafter就是AOP提供给我们的方面、切面的某种表现形式,明白了嘛?

没明白!

......

那我抽时间再弄点别的例子吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值