极光推送Java SDK源码学习
2016-06-04 11:03
633 查看
前一段时间使用JPush搞了一下推送,服务器用的SpringMVC,所以想看看他的SDK源码。结果呢,一般般,没有很惊艳的感觉,看别人的代码总想去批评,这不好,但是有点失望吧~~
JPush核心有两个部分,一个是JPushClient,一个是Payload
这四个Client都是使用NativeHttpClient实现发送的,NativeHttpClient实现了IHttpClient接口
而NativeHttpClient的核心代码使用了HttpURLConnection,没有连接池,JPush的服务器使用了Yii做流量控制,这些我们都没办法改变
PushPayload是推送的内容,使用builder模式,分为以下几个属性:
Platform表示推送平台,ios,Android,wp
Audience表示接受者,可以有别名,标签等方式
Notification表示接受推送的一些定制,比如声音之类的(这里面还需要根据不同的平台设置,感觉和Platform有些重复)
Message表示消息具体内容
Options表示额外选项
SMS表示短信
设计了过多的model,但是却没有一个舒服的继承关系
很多都是这样,而且重复
Result的Model为什么不能统一下一,搞了好多。。这样不行吗
命名太尴尬,”_”符号我明白是内部实现的意思,但这是java啊!private不就够了,这种C的命名看起来累人!
如果你是JPush Java SDK的开发人员,别打我- -b
任何逃开实际开发环境的讨论代码都是耍流氓,这个我懂,但是我还是失望了
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<T> 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
任何逃开实际开发环境的讨论代码都是耍流氓,这个我懂,但是我还是失望了
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 从源码安装Mysql/Percona 5.5
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序