spring3 restful 服务迁移到 spring4需要注意的事项
摘要: Spring4 对MVC 应用进行了一些改进, 首先测试了在restful 服务上的改进, 至少目前看来需要注意的有如下两点:1. 从@ResponseBody 改成 @RestController2. Synchronous 和 Asynchronous 调用,也就是同步异步调用.
Spring4 对MVC 应用进行了一些改进, 首先测试了在restful 服务上的改进, 至少目前看来需要注意的有如下两点:
1. 从@ResponseBody 改成 @RestController
2. Synchronous 和 Asynchronous 调用,也就是同步异步调用.
下面是从spring3 mvc 迁移到 spring4 mvc 工程的系列步骤:
1. 引入 spring 4 的jar 包,如果是 maven 的话,用spring4的依赖
org.springframework spring-context 4.0.0.RELEASE org.springframework spring-webmvc 4.0.0.RELEASE
2. 引入 servlet 3.0 的依赖包
这个比较重要,spring4 的有些特性是在 servlet3.0 上实现的。
javax.servlet javax.servlet-api 3.1.0
3. 更改spring 的命名空间
记得一定在 xml 配置文件里面修改
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
4. jackson 版本的变化,一定要采用2.0 以上版本
com.fasterxml.jackson.core jackson-core 2.3.0 com.fasterxml.jackson.core jackson-databind 2.3.0
另外,如果你是显示的注册了message convert, 那么你还得自己配置如下代码, 因为jackson 1.x 版本已经过期了:
//converters.add(new MappingJacksonHttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter());
5. 可以在类级别上实现@ResponseBody 注解,下面的方法自动继承这个注解,不需要都配置
@Controller @ResponseBody public class SeriesController { ... }
上面的配置可以用一个更简单的方法来配置, 这两者是等价的.
@RestController public class SeriesController { ... }
6. RestTemplate 调用 restful service 时的异步解决方法,和处理回调函数
在使用 RestTemplate 调用 restful service 时将会阻塞, 直到得到结果。在spring4 中增加了异步调用方法, 在调用方法的过程中,仍然可以执行其他计算,在后面在获取得到的结果
@Test public void getAllSeriesAsync() throws InterruptedException, ExecutionException { logger.info("Calling async /series"); Future> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class); logger.info("Doing other async stuff..."); logger.info("Blocking to receive response..."); ResponseEntity entity = futureEntity.get(); logger.info("Response received"); Series[] series = entity.getBody(); assertNotNull(series); assertEquals(2, series.length); assertEquals(1L, series[0].getId()); assertEquals("The walking dead", series[0].getName()); assertEquals("USA", series[0].getCountry()); assertEquals("Thriller", series[0].getGenre()); assertEquals(2L, series[1].getId()); assertEquals("Homeland", series[1].getName()); assertEquals("USA", series[1].getCountry()); assertEquals("Drama", series[1].getGenre()); }
虽然上面的方法解决了异步调用,但在得到结果的 futureEntity.get() 方法还是会阻塞的,如果结果还没有得到的话。 其实这里用到的就是 多线程里面的 Future 模式,你可以看到 RestTemplate 返回的是 ListenableFuture, 这个类是可以注册一个回调函数的,把结果交给回调函数去处理. 如下例子:
@Test public void getAllSeriesAsyncCallable() throws InterruptedException, ExecutionException { logger.info("Calling async callable /series"); ListenableFuture> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class); futureEntity.addCallback(new ListenableFutureCallback >() { @Override public void onSuccess(ResponseEntity entity) { logger.info("Response received (async callable)"); Series[] series = entity.getBody(); validateList(series); } @Override public void onFailure(Throwable t) { fail(); } }); logger.info("Doing other async callable stuff ..."); Thread.sleep(6000); //waits for the service to send the response }
这样就能成功的将spring3 工程转移到 sping4 下面,其实改动并不多.