您的位置:首页 > 编程语言 > Java开发

Spring4 Retrofit2 整合

2016-06-30 08:56 411 查看


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
[/code]


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
[/code]
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
[/code]
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));
}
}
1
2
3
4
5
6
7
8
[/code]


工厂生产的实体类

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
[/code]


工厂类

public class RetrofitBeanFactory {
//key:请求地址 value:当前请求地址下class所对应的service(key:class value:service)
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
[/code]


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
[/code]


自定义注解

/**
* Created by zhangbowen on 2016/5/12.
* 用于标识服务接口类
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface HttpApi {
String value() default "";//通过key获得配置文件中的值
Class[] interceptor() default {};
}
1
2
3
4
5
6
7
8
9
10
[/code]
/**
* Created by zhangbowen on 2016/5/12.
* 用于自动注入服务
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HttpService {
}
1
2
3
4
5
6
7
8
[/code]


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;
}
//根据注解的key获得配置文件中的url
Object value = propertyConfigurer.getProperty(key);
if (value == null) {
return;
}
//根据地址创建retrofit
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
[/code]


3.在spring.config中注册组件

<!--注册加载retrofit服务的processor 只能在非controller中使用-->
<bean id="retrofitProcessor" class="com.miyan.common.modules.retrofit.processor.RetrofitAutowiredProcessor"></bean>
1
2
[/code]


4. 使用


Maven

Spring的就不再引入,建议使用Spring4,引入retrofit2框架
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.0.2</version>
</dependency>
1
2
3
4
5
[/code]


properties

定义服务的地址
IM_BASE_URL=https://a1.easemob.com/huapingxin2015/miyan/
1
[/code]


创建retrofit服务接口

//IM_BASE_URL在配置文件中配置
//interceptor 为可选参数,与retrofit拦截器相同,实现拦截http
@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
[/code]


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
[/code]


在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
[/code]


5.小结

仅仅是将retrofit整合进spring,并没有扩展retortfit功能,通过BeanPostProcessor的子实现类InstantiationAwareBeanPostProcessor的生命周期postProcessAfterInstantiation实现,其中用到的拦截器,定义服务接口中的注解以及请求都是retorfit2.0中提供的。retrofit2.0是Android中比较流行的网络框架,是对okhttp的再次封装

与spring整合后,web应用中调用三方接口的网络请求会简单清晰很多,比自己封装的网络框架好很多

附retorfit github:

http://square.github.io/retrofit/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: