Spring4 Retrofit2 整合
组件结构
开始spring实例化bean后实例化带有HttpService注解的类(实际为retrofit动态代理类)结束
实现
1.构造retrofit工厂用于创建服务
Retrofit LoggingInterceptor日期拦截器
public class LoggingInterceptor implements Interceptor {
private static Logger logger = Logger.getLogger(LoggingInterceptor.class);
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
logger.info(String.format("发送请求:%s%n请求头:%s",
request.url(), request.headers()));
Response response = chain.proceed(request);
return response;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
Retrofit FastJson转换器
public class FastJsonConverterFactory extends Converter.Factory{
public static FastJsonConverterFactory create() {
return new FastJsonConverterFactory();
}
/** * 需要重写父类中responseBodyConverter,该方法用来转换服务器返回数据 */
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new FastJsonResponseBodyConverter<>(type);
}
/** * 需要重写父类中responseBodyConverter,该方法用来转换发送给服务器的数据 */
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new FastJsonRequestBodyConverter<>();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
public class FastJsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Type type;
public FastJsonResponseBodyConverter(Type type) {
this.type = type;
}
@Override
public T convert(ResponseBody value) throws IOException {
BufferedSource bufferedSource = Okio.buffer(value.source());
String tempStr = bufferedSource.readUtf8();
bufferedSource.close();
try {
return JSON.parseObject(tempStr, type);
}catch (JSONException e){
return (T) tempStr;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
public class FastJsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
@Override
public RequestBody convert(T value) throws IOException {
return RequestBody.create(MEDIA_TYPE, JSON.toJSONBytes(value));
}
}
工厂生产的实体类
public class RetrofitBean {
private Retrofit retrofit;
private Map<Class,Object> service = new HashMap<>();
public Retrofit getRetrofit() {
return retrofit;
}
public void setRetrofit(Retrofit retrofit) {
this.retrofit = retrofit;
}
public Map<Class, Object> getService() {
return service;
}
public void setService(Map<Class, Object> service) {
this.service = service;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
工厂类
public class RetrofitBeanFactory {
private static Map<String, RetrofitBean> resolvableDependencies = new HashMap(16);
private static final int readTimeOut = 15;
private static final int writeTimeOut = 15;
private static final int connTimeOut = 15;
/** * 获得service服务实体 * * @param requiredType * @return * @throws BeansException */
public static Object getBean(Class requiredType) throws BeansException {
for (Map.Entry<String, RetrofitBean> entrySet : resolvableDependencies.entrySet()) {
RetrofitBean retrofitBean = entrySet.getValue();
for (Map.Entry<Class, Object> serviceSet : retrofitBean.getService().entrySet()) {
if (requiredType == serviceSet.getKey()) {
return serviceSet.getValue();
}
}
}
return null;
}
/** * 创建service服务实体 * * @param baseUrl * @param serviceClass */
public static Object putBean(String baseUrl, Class serviceClass, Class... interceptorClass) {
if (StringUtils.isEmpty(baseUrl)) {
return null;
}
RetrofitBean retrofitBean = resolvableDependencies.get(baseUrl);
if (retrofitBean == null) {
retrofitBean = new RetrofitBean();
OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder()
.connectTimeout(readTimeOut, TimeUnit.SECONDS)
.writeTimeout(writeTimeOut, TimeUnit.SECONDS)
.readTimeout(connTimeOut, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor());
if (interceptorClass != null && interceptorClass.length > 0) {
for (Class clazz : interceptorClass) {
if (Interceptor.class.isAssignableFrom(clazz)) {
try {
clientBuilder.addInterceptor((Interceptor) clazz.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(clientBuilder.build())
.addConverterFactory(FastJsonConverterFactory.create())
.build();
retrofitBean.setRetrofit(retrofit);
resolvableDependencies.put(baseUrl, retrofitBean);
}
Retrofit retrofit = retrofitBean.getRetrofit();
Object bean = retrofit.create(serviceClass);
retrofitBean.getService().put(serviceClass, bean);
return bean;
}
public static Map<String, RetrofitBean> getResolvableDependencies() {
return resolvableDependencies;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
2.扩展spring生命周期
自定义配置文件读取工具
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private Properties props;
@Override
protected void processProperties(
ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException {
super.processProperties(beanFactory, props);
this.props = props;
}
public Object getProperty(String key) {
return props.get(key);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
自定义注解
/** * Created by zhangbowen on 2016/5/12. * 用于标识服务接口类 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface HttpApi {
String value() default "";
Class[] interceptor() default {};
}
/** * Created by zhangbowen on 2016/5/12. * 用于自动注入服务 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HttpService {
}
spring注入实体后的回调方法
public class RetrofitAutowiredProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private Logger logger = Logger.getLogger(RetrofitAutowiredProcessor.class);
@Autowired
private CustomPropertyPlaceholderConfigurer propertyConfigurer;
@Override
public boolean postProcessAfterInstantiation(final Object bean, final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
HttpService httpApi = field.getAnnotation(HttpService.class);
if (httpApi == null) {
return;
}
createRetrofitService(bean, field, field.getType());
}
});
return super.postProcessAfterInstantiation(bean, beanName);
}
private void createRetrofitService(Object bean, Field field, Class clazz) throws IllegalAccessException {
HttpApi httpApi = (HttpApi) clazz.getAnnotation(HttpApi.class);
String key = httpApi.value();
if (StringUtils.isBlank(key)) {
return;
}
Object value = propertyConfigurer.getProperty(key);
if (value == null) {
return;
}
Object object = RetrofitBeanFactory.putBean(value.toString(), clazz,httpApi.interceptor());
if (object == null) {
return;
}
field.setAccessible(true);
field.set(bean, object);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
3.在spring.config中注册组件
<bean id="retrofitProcessor" class="com.miyan.common.modules.retrofit.processor.RetrofitAutowiredProcessor"></bean>
4. 使用
Maven
Spring的就不再引入,建议使用Spring4,引入retrofit2框架
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.0.2</version>
</dependency>
properties
定义服务的地址
IM_BASE_URL=https://a1.easemob.com/huapingxin2015/miyan/
创建retrofit服务接口
@HttpApi(value = "IM_BASE_URL", interceptor = {ImInterceptor.class})
public interface IMApi {
/** * 修改群组信息 * * @param updateGroupInfoBean * @param groupId * @return */
@PUT("chatgroups/{group_id}")
Call<String> updateGroup(@Body UpdateGroupInfoBean updateGroupInfoBean, @Path("group_id") String groupId);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
ImInterceptor
/** * Created by zhangbowen on 2016/5/17. * 环信公用请求头拦截器 */
public class ImInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String token = CacheFacade.getObject(Constants.IM.TOKEN);
Request request = originalRequest
.newBuilder()
.addHeader(Constants.Http.AUTHORIZATION, "Bearer " + token)
.build();
return chain.proceed(request);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
在Service层中使用
/** * Created by zhangbowen on 2016/1/21. * 环信及时通讯服务 */
@Service
public class IMService {
@HttpService
private IMApi imApi;
/** * 修改群组信息 * * @param updateGroupInfoBean * @param groupId */
public void updateGroupInfo(UpdateGroupInfoBean updateGroupInfoBean, String groupId) {
try {
imApi.updateGroup(updateGroupInfoBean, groupId).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
5.小结
仅仅是将retrofit整合进spring,并没有扩展retortfit功能,通过BeanPostProcessor的子实现类InstantiationAwareBeanPostProcessor的生命周期postProcessAfterInstantiation实现,其中用到的拦截器,定义服务接口中的注解以及请求都是retorfit2.0中提供的。retrofit2.0是Android中比较流行的网络框架,是对okhttp的再次封装
与spring整合后,web应用中调用三方接口的网络请求会简单清晰很多,比自己封装的网络框架好很多
附retorfit github:
http://square.github.io/retrofit/