极光java sdk_极光推送Java SDK源码学习

本文介绍了JPush的Java SDK,重点关注JPushClient及其内部的四个Client,它们使用NativeHttpClient实现发送。同时,文章指出SDK没有使用连接池,并讨论了设计模式和Model的组织结构,对于SDK的优化提出了建议。
摘要由CSDN通过智能技术生成

前一段时间使用JPush搞了一下推送,服务器用的SpringMVC,所以想看看他的SDK源码。结果呢,一般般,没有很惊艳的感觉,看别人的代码总想去批评,这不好,但是有点失望吧~~

JPush核心有两个部分,一个是JPushClient,一个是Payload

JPushClient

内部有四个属性PushClient,ReportClient,DeviceClient,ScheduleClient。

这四个Client都是使用NativeHttpClient实现发送的,NativeHttpClient实现了IHttpClient接口

public interface IHttpClient {

public static final String CHARSET = "UTF-8";

public static final String CONTENT_TYPE_JSON = "application/json";

public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";

public static final String RATE_LIMIT_QUOTA = "X-Rate-Limit-Limit";

public static final String RATE_LIMIT_Remaining = "X-Rate-Limit-Remaining";

public static final String RATE_LIMIT_Reset = "X-Rate-Limit-Reset";

public static final String JPUSH_USER_AGENT = "JPush-API-Java-Client";

public static final int RESPONSE_OK = 200;

public enum RequestMethod {

GET,

POST,

PUT,

DELETE

}

public static final String IO_ERROR_MESSAGE = "Connection IO error. \n"

+ "Can not connect to JPush Server. "

+ "Please ensure your internet connection is ok. \n"

+ "If the problem persists, please let us know at support@jpush.cn.";

public static final String CONNECT_TIMED_OUT_MESSAGE = "connect timed out. \n"

+ "Connect to JPush Server timed out, and already retried some times. \n"

+ "Please ensure your internet connection is ok. \n"

+ "If the problem persists, please let us know at support@jpush.cn.";

public static final String READ_TIMED_OUT_MESSAGE = "Read timed out. \n"

+ "Read response from JPush Server timed out. \n"

+ "If this is a Push action, you may not want to retry. \n"

+ "It may be due to slowly response from JPush server, or unstable connection. \n"

+ "If the problem persists, please let us know at support@jpush.cn.";

public static Gson _gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

//设置连接超时时间

public static final int DEFAULT_CONNECTION_TIMEOUT = (5 * 1000); // milliseconds

//设置读取超时时间

public static final int DEFAULT_READ_TIMEOUT = (30 * 1000); // milliseconds

public static final int DEFAULT_MAX_RETRY_TIMES = 3;

public ResponseWrapper sendGet(String url)

throws APIConnectionException, APIRequestException;

public ResponseWrapper sendDelete(String url)

throws APIConnectionException, APIRequestException;

public ResponseWrapper sendPost(String url, String content)

throws APIConnectionException, APIRequestException;

public ResponseWrapper sendPut(String url, String content)

throws APIConnectionException, APIRequestException;

}

而NativeHttpClient的核心代码使用了HttpURLConnection,没有连接池,JPush的服务器使用了Yii做流量控制,这些我们都没办法改变

private ResponseWrapper _doRequest(String url, String content,

RequestMethod method) throws APIConnectionException, APIRequestException,

SocketTimeoutException {

LOG.debug("Send request - " + method.toString() + " "+ url);

if (null != content) {

LOG.debug("Request Content - " + content);

}

HttpURLConnection conn = null;

OutputStream out = null;

StringBuffer sb = new StringBuffer();

ResponseWrapper wrapper = new ResponseWrapper();

try {

URL aUrl = new URL(url);

if (null != _proxy) {

conn = (HttpURLConnection) aUrl.openConnection(_proxy.getNetProxy());

if (_proxy.isAuthenticationNeeded()) {

conn.setRequestProperty("Proxy-Authorization", _proxy.getProxyAuthorization());

}

} else {

conn = (HttpURLConnection) aUrl.openConnection();

}

conn.setConnectTimeout(_connectionTimeout);

conn.setReadTimeout(_readTimeout);

conn.setUseCaches(false);

conn.setRequestMethod(method.name());

conn.setRequestProperty("User-Agent", JPUSH_USER_AGENT);

conn.setRequestProperty("Connection", "Keep-Alive");

conn.setRequestProperty("Accept-Charset", CHARSET);

conn.setRequestProperty("Charset", CHARSET);

conn.setRequestProperty("Authorization", _authCode);

conn.setRequestProperty("Content-Type", CONTENT_TYPE_JSON);

if(null == content) {

conn.setDoOutput(false);

} else {

conn.setDoOutput(true);

byte[] data = content.getBytes(CHARSET);

conn.setRequestProperty("Content-Length", String.valueOf(data.length));

out = conn.getOutputStream();

out.write(data);

out.flush();

}

int status = conn.getResponseCode();

InputStream in = null;

if (status / 100 == 2) {

in = conn.getInputStream();

} else {

in = conn.getErrorStream();

}

if (null != in) {

InputStreamReader reader = new InputStreamReader(in, CHARSET);

char[] buff = new char[1024];

int len;

while ((len = reader.read(buff)) > 0) {

sb.append(buff, 0, len);

}

}

String responseContent = sb.toString();

wrapper.responseCode = status;

wrapper.responseContent = responseContent;

String quota = conn.getHeaderField(RATE_LIMIT_QUOTA);

String remaining = conn.getHeaderField(RATE_LIMIT_Remaining);

String reset = conn.getHeaderField(RATE_LIMIT_Reset);

wrapper.setRateLimit(quota, remaining, reset);

if (status >= 200 && status < 300) {

LOG.debug("Succeed to get response OK - responseCode:" + status);

LOG.debug("Response Content - " + responseContent);

} else if (status >= 300 && status < 400) {

LOG.warn("Normal response but unexpected - responseCode:" + status + ", responseContent:" + responseContent);

} else {

LOG.warn("Got error response - responseCode:" + status + ", responseContent:" + responseContent);

switch (status) {

case 400:

LOG.error("Your request params is invalid. Please check them according to error message.");

wrapper.setErrorObject();

break;

case 401:

LOG.error("Authentication failed! Please check authentication params according to docs.");

wrapper.setErrorObject();

break;

case 403:

LOG.error("Request is forbidden! Maybe your appkey is listed in blacklist or your params is invalid.");

wrapper.setErrorObject();

break;

case 404:

LOG.error("Request page is not found! Maybe your params is invalid.");

wrapper.setErrorObject();

break;

case 410:

LOG.error("Request resource is no longer in service. Please according to notice on official website.");

wrapper.setErrorObject();

case 429:

LOG.error("Too many requests! Please review your appkey's request quota.");

wrapper.setErrorObject();

break;

case 500:

case 502:

case 503:

case 504:

LOG.error("Seems encountered server error. Maybe JPush is in maintenance? Please retry later.");

break;

default:

LOG.error("Unexpected response.");

}

throw new APIRequestException(wrapper);

}

} catch (SocketTimeoutException e) {

if (e.getMessage().contains(KEYWORDS_CONNECT_TIMED_OUT)) {

throw e;

} else if (e.getMessage().contains(KEYWORDS_READ_TIMED_OUT)) {

throw new SocketTimeoutException(KEYWORDS_READ_TIMED_OUT);

}

LOG.debug(IO_ERROR_MESSAGE, e);

throw new APIConnectionException(IO_ERROR_MESSAGE, e);

} catch (IOException e) {

LOG.debug(IO_ERROR_MESSAGE, e);

throw new APIConnectionException(IO_ERROR_MESSAGE, e);

} finally {

if (null != out) {

try {

out.close();

} catch (IOException e) {

LOG.error("Failed to close stream.", e);

}

}

if (null != conn) {

conn.disconnect();

}

}

return wrapper;

}

PushPayload

private final Platform platform;

private final Audience audience;

private final Notification notification;

private final Message message;

private Options options;

private SMS sms;

PushPayload是推送的内容,使用builder模式,分为以下几个属性:

Platform表示推送平台,ios,Android,wp

Audience表示接受者,可以有别名,标签等方式

Notification表示接受推送的一些定制,比如声音之类的(这里面还需要根据不同的平台设置,感觉和Platform有些重复)

Message表示消息具体内容

Options表示额外选项

SMS表示短信

也许是建议

没有连接池

设计了过多的model,但是却没有一个舒服的继承关系

很多都是这样,而且重复

public interface PushModel {

public static Gson gson = new Gson();

public JsonElement toJSON();

}

public interface IModel {

public JsonElement toJSON();

}

Result的Model为什么不能统一下一,搞了好多。。这样不行吗

public class ResultCode implements Serializable {

private String errMsg;

private int errCode;

private T data;

}

命名太尴尬,”_”符号我明白是内部实现的意思,但这是java啊!private不就够了,这种C的命名看起来累人!

private final NativeHttpClient _httpClient;

private String _baseUrl;

private String _pushPath;

private String _pushValidatePath;

如果你是JPush Java SDK的开发人员,别打我- -b 任何逃开实际开发环境的讨论代码都是耍流氓,这个我懂,但是我还是失望了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值