事务、缓存和AOP:理解Spring中的代理使用

工程 | Michael Isvy | 2012年5月23日 | ...

在Spring框架中,许多技术特性都依赖于代理使用。我们将使用三个示例深入探讨这个主题:事务缓存Java配置

这篇博客文章中显示的所有代码示例都可以在我的github帐户上找到。

事务

第一步:无事务

下面的Service类尚未事务化。让我们首先看看它的原样,然后使其事务化。

@Service
public class AccountServiceImpl  implements AccountService {
 //…

//Not specifying a transaction policy here!
 public void create(Account account) {
 entityManager.persist(account);
 }
}

由于“create”方法不是事务化的,它很可能会抛出异常(因为这个Account对象不应该……

本周 Spring - 2012 年 5 月 22 日

工程 | Josh Long | 2012 年 5 月 22 日 | ...

欢迎阅读本期《本周 Spring》的又一次更新。和往常一样,我们有很多精彩的内容要分享!

  1. Rossen Stoyanchev 在他关于 Spring MVC 3.2 预览系列的博客文章中又发布了一篇新博文。这最新一期介绍了 一个 Spring MVC 聊天示例
  2. Oliver Gierke 宣布了 Spring Data JPA 的 1.1.0 GA 版本。Spring Data JPA 可以非常简单地构建基于 JPA 的仓库,从而节省了您编写样板代码的繁琐工作。此新版本包括用于查询生成的关键字(LessThanEqualGreaterThanEqualBeforeAfterStartsWithEndsWithContains)、一个用于扫描 JPA 实体的方便的 PersistenceUnitPostProcessor(用于 Spring 3.1 之前的版本)、对 @Query 中原生查询的支持以及对声明式锁定的支持。
  3. Jonathan Brisbin 宣布了 Spring Data REST 的 1.0.0.M2 版本。Spring Data REST 可以让您轻松地将 Spring 仓库对象导出为 RESTful 端点。新版本包括对调用 Repository 接口的查询方法、对 JSR 303 和 Spring Validator 验证的支持,以及对每次保存或删除之前和之后发出的 Spring ApplicationEvent 的改进支持,还有基于注解的配置。
  4. Oleg Zhurakousky 宣布了 Spring Integration 2.2 的第一个里程碑版本。此版本包括依赖项升级、JPA 支持以及对“发布者确认和退回”的支持,这些功能在 Spring AMQP 中是新支持的。
  5. Gary Russell 宣布了 Spring AMQP 的 1.1.0 版本,其中包括对 RabbitMQ 2.8.x 客户端的支持,该客户端进而支持镜像队列、代理故障转移、发布者确认、退回、联合交换等更多功能。
  6. Matt Vickery 发布了一篇精彩的文章,介绍了 Spring Integration 的 splitter-aggregator 模式
  7. Willie Wheeler 在他的博客上发布了一篇关于他 自定义配置管理数据库 (CMDB) 的精彩文章。文章详细介绍了该项目,然后讨论了他如何使用 Spring Data 的仓库来重建 CMDB 的后端。写得好,Willie!
  8. Doug Haber 整理了一篇精彩的文章,介绍了 如何使用 Spring Data 和 Spring 3.1 中的 REST 支持来处理分页
  9. 博主 panbhatt 发布了一篇详细的文章,介绍了如何使用 Spring MVC 的 REST 支持来解决他遇到的特定问题。
  10. 博主 OBSERWATORZY 描述了他在 尝试消费 RESTful 服务时的一些思考过程,并想知道 Spring 是否提供了解决方案(当然,它提供了!)。请继续阅读他的解决方案。
  11. Vishal Biyani 发布了一个很好的入门指南,介绍了 如何开始使用 Spring Roo 和 Cloud Foundry
  12. RabbitMQ 博客上有一篇很棒的文章 介绍了排队论(包括吞吐量、延迟和带宽的介绍
  13. JAXEnter 汇总了 本文中提到的一些新闻发布情况,包括 Spring AMQP 和 Spring Data JPA 的 GA 版本。

本周 Spring,2012 年 5 月 15 日

工程 | Josh Long | 2012年5月16日 | ...

欢迎阅读本期《本周 Spring!》。和往常一样,我们有很多内容要介绍。那么,继续吧!

  1. Rossen Stoyanchev 发布了他的博客系列第二部分和第三部分,介绍了 Spring MVC 3.2 的新功能。在第一部分中,Rossen 介绍了如何让 Spring MVC @Controller 异步。在第二篇文章中,Rossen 介绍了 如何为现有 Web 应用程序添加长轮询。长轮询在任何需要模拟客户端应用程序的服务器端推送的场景中都很有用。
  2. <LI>  The video for <a href= "http://blog.springsource.org/author/ozhurakousky/">Oleg Zhurakousky</A>'s followup webinar introducing <a href ="http://www.springsource.org/node/3550">More Practical Tips and Tricks with Spring Integration</A> has just been posted. Check it out! </LI> 
     <LI> <A href ="http://blog.springsource.org/author/rclarkson/">Roy Clarkson</A>  just announced that <a href = "http://www.springsource.org/spring-mobile/news/1.0.0-released">Spring Mobile 1.0.0 has  been released</A>!  </LI>
    
    
    
    <LI>  SpringSource and Cloud Foundry rockstar  <a  href  ="http://blog.springsource…

Spring MVC 3.2 预览:聊天示例

工程 | Rossen Stoyanchev | 2012年5月16日 | ...

最后更新于 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

在前 几篇 文中,我介绍了 Spring MVC 3.2 中基于 Servlet 3 的异步功能,并使用了 spring-mvc-showcase 和 Spring AMQP 的 stocks 示例 来演示它。本文介绍了一个聊天示例,其中外部事件不是 AMQP 消息,而是带有聊天消息的 HTTP POST 请求。在文章的第二部分,我将切换到一个分布式聊天,其中事件是 Redis 通知。

聊天并不是 Web 应用程序的常见需求。然而,它是一个只能通过实时通知满足的需求的良好示例。它比电子邮件或状态警报对时间延迟更敏感,而且在浏览器中与朋友聊天,或者在网络研讨会期间与同事聊天,或者与购物网站上的真人聊天的情况并不少见。您可以想象其他类型的在线协作。

示例

spring-mvc-chat 示例在 Github 上可用。虽然不是本文的重点,但客户端使用了 Thymeleafknockout.js 和 jQuery。Thymeleaf 是 JSP 的一个极好的替代品,它支持干净的 HTML 模板,并支持预览,允许设计师双击 HTML 模板查看它,而不像 JSP 需要 Servlet 容器。knockout.js 是一个客户端 MVC 框架,非常方便地为 HTML 元素添加行为。要快速了解它,请遵循其出色的 教程 之一。jQuery 用于 DOM 脚本和 Ajax 请求。

ChatController

ChatController 暴露了获取和发布聊天消息的操作。这是获取消息的方法:


@RequestMapping(method=RequestMethod.GET)
@ResponseBody
public DeferredResult<List<String>> getMessages(@RequestParam int messageIndex) {

  final DeferredResult<List<String>> deferredResult = new DeferredResult<List<String>>(null, Collections.emptyList());
  this.chatRequests.put(deferredResult, messageIndex);

  deferredResult.onCompletion(new Runnable() {
    @Override
    public void run() {
      chatRequests.remove(deferredResult);
    }
  });

  List<String> messages = this.chatRepository.getMessages…

Spring MVC 3.2 预览:为现有 Web 应用程序添加长轮询

工程 | Rossen Stoyanchev | 2012年5月14日 | ...

最后更新于 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

在我的上一篇博文中,我讨论了如何通过返回一个由 Spring MVC 在单独线程中调用的Callable来使 Spring MVC 控制器方法异步。

但是,如果异步处理依赖于接收一个 Spring MVC 未知的线程中的外部事件——例如,接收 JMS 消息、AMQP 消息、Redis pub-sub 通知、Spring Integration 事件等等,该怎么办?我将通过修改Spring AMQP项目中的现有示例来探索这种情况。

示例

Spring AMQP 有一个股票交易示例,其中 QuoteController 通过 Spring AMQP 的RabbitTemplate发送交易执行消息,并通过 Spring AMQP 的 RabbitMQ listener container以消息驱动的 POJO 样式接收交易确认和价格报价消息。

在浏览器中,该示例使用轮询来显示价格报价。对于交易,初始请求提交交易并返回一个确认 ID,然后使用该 ID 轮询以获取最终确认。我已经更新了该示例,以利用 Spring 3.2 Servlet 3 异步支持。 master 分支包含更改前的代码,而 spring-mvc-async 分支包含更改后的代码。下图显示了价格报价请求频率(使用 Chrome 开发者工具)的变化。

更改前:传统轮询

更改后:长轮询

正如您所见,通过常规轮询,新请求非常频繁地发送(间隔毫秒),而在长轮询中,请求可以间隔 5、10、20 秒或更长时间——总请求数量显著减少,同时不损失延迟,即新价格报价出现在浏览器中的时间量。

获取报价

那么需要进行哪些更改呢?从客户端的角度来看,传统轮询和长轮询是无法区分的,因此 HTML 和 JavaScript 没有改变。从服务器的角度来看,请求必须被挂起,直到新的报价到达。这是控制器处理报价请求的方式。



// Class field
private Map<String, DeferredResult> suspendedTradeRequests = new ConcurrentHashMap<String, DeferredResult>();

...

@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<List<Quote>> quotes(@RequestParam(required = false) Long timestamp) {

  final DeferredResult<List<Quote>> result = new DeferredResult<List<Quote>>(null, Collections.emptyList());
  this.quoteRequests.put(result, timestamp);

  result.onCompletion(new Runnable() {
    public void run() {
      quoteRequests…

Spring MVC 3.2 预览:使控制器方法异步

工程 | Rossen Stoyanchev | 2012 年 5 月 10 日 | ...

最后更新于 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

之前的博文中,我介绍了 Spring MVC 3.2 中基于 Servlet 3 的异步功能,并讨论了实时更新的技术。在本文中,我将深入探讨技术细节,并讨论异步处理如何融入 Spring MVC 请求生命周期。

快速回顾一下,您可以通过将任何现有控制器方法更改为返回一个Callable来使其异步。例如,一个返回视图名称的控制器方法可以改为返回 Callable<String>。一个返回名为 Person 的对象的 @ResponseBody 可以改为返回 Callable<Person>。对于任何其他控制器返回值类型,情况也是如此。

核心思想是,您对控制器方法如何工作的所有已知内容都将尽可能保持不变,只是其余的处理将在另一个线程中进行。在异步执行方面,保持简单非常重要。正如您将看到的,即使是这种看似简单的编程模型更改,也有很多需要考虑的地方。

spring-mvc-showcase 已针对 Spring MVC 3.2 更新。请查看 CallableController。诸如 @ResponseBody@ResponseStatus 等方法注解也适用于 Callable 的返回值,正如您所料。从 Callable 引发的异常将像从控制器引发的异常一样被处理,在这种情况下使用 @ExceptionHandler 方法。等等。

如果您通过浏览器中的“Async Requests”选项卡执行 CallableController 方法之一,您应该会看到与下图类似的输出。

08:25:15 [http-bio-8080-exec-10] DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [...]
08:25:15 [http-bio-8080-exec-10] RequestMappingHandlerMapping - Looking up handler method for path /async/callable/view
08:25:15 [http-bio-8080-exec-10] RequestMappingHandlerMapping - Returning handler method [...]
08:25:15 [http-bio-8080-exec-10] WebAsyncManager - Concurrent handling starting for GET [...]
08:25:15 [http-bio-8080-exec-10] DispatcherServlet - Leaving response open for concurrent…

将 Cloud Foundry Workers 与 Spring 结合使用

工程 | Josh Long | 2012 年 5 月 9 日 | ...

您无疑已经阅读了Jennifer Hickey关于介绍 Cloud Foundry workers、它们在设置Ruby Resque 后台作业中的应用,以及今天关于介绍 Spring 支持的博文

Spring 开发人员的关键要点

  1. 您需要更新您的 vmc 版本,执行 gem update vmc
  2. Cloud Foundry workers 允许您运行 public static void main 作业。也就是说,Cloud Foundry worker 本质上是一个进程,比 Web 应用程序低级,这自然适用于许多所谓的后台作业。
  3. 您需要提供 Cloud Foundry 将运行的命令。您可以提供所需的 java 命令,但更简单的方法是打包一个 shell 脚本,然后让 Cloud Foundry 为您运行该 shell 脚本。您提供的命令应使用 $JAVA_OPTS,Cloud Foundry 已提供该选项以确保一致的内存使用和 JVM 设置。
  4. 有多种方法可以自动化创建可部署的 Cloud Foundry 应用程序。如果您使用 Maven,那么 org.codehaus.mojo:appassembler-maven-plugin 插件将帮助您创建启动脚本并打包您的 .jars 以便轻松部署,同时还可以指定入口点类。
  5. 其他一切基本相同。当您在 Java .jar 项目上执行 vmc push 时,Cloud Foundry 会询问您该应用程序是否为独立应用程序。确认后,它会引导您完成后续设置。

因此,让我们来看一些使用 Cloud Foundry workers 更容易、更自然的常见体系结构和安排。我们将从 Spring 框架和两个周边项目 Spring Integration 和 Spring Batch 的角度来看这些模式,这两个项目都在 Web 应用程序内部和外部蓬勃发展。正如我们将看到的,这两个框架都支持解耦和改进的可组合性。我们将分离什么发生与何时发生,并将分离什么发生与何处发生,所有这些都是为了释放前端的容量。

我有一个计划要遵守!

我经常收到一个常见问题:如何在 Cloud Foundry 上进行作业调度? Cloud Foundry 支持 Spring 应用程序,而 Spring 当然一直支持企业级的调度抽象,如 Quartz 和 Spring 3.0 的 @Scheduled 注解。@Scheduled 非常好用,因为它极其容易添加到现有应用程序中。最简单的做法是,将 @EnableScheduling 添加到您的 Java 配置中,或者将 <task:annotation-driven/> 添加到您的 XML 中,然后在代码中使用 @Scheduled 注解。这在企业应用程序中非常自然,也许您有一个需要运行的分析或报告过程?一些耗时长的批处理过程?我准备了一个示例,演示了如何使用 @Scheduled 来运行 Spring Batch Job。Spring Batch 作业本身是一个工作线程,它与一个 Web 服务一起工作,而该 Web 服务糟糕的 SLA 使其不适合实时使用。在 Spring Batch 中处理工作更安全、更干净,因为它的恢复和重试功能可以弥补任何网络中断、网络延迟等问题。关于大部分细节,我将参考 代码示例,我们只会看一下入口点,然后看看如何将应用程序部署到 Cloud Foundry。

					    
// set to every 10s for testing.
@Scheduled(fixedRate = 10 * 1000)
public void runNightlyStockPriceRecorder() throws Throwable {
	JobParameters params = new JobParametersBuilder()
		.addDate("date", new Date())
		.toJobParameters();
	JobExecution jobExecution = jobLauncher.run(job, params);
	BatchStatus batchStatus = jobExecution.getStatus();
	while (batchStatus.isRunning()) {
		logger.info("Still running...");
		Thread.sleep(1000);
	}
	logger.info(String.format("Exit status: %s", jobExecution.getExitStatus().getExitCode()));
	JobInstance jobInstance = jobExecution.getJobInstance…

Spring MVC 3.2 预览:实时更新技术

工程 | Rossen Stoyanchev | 2012 年 5 月 8 日 | ...

最后更新于 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

在上一篇博文中,我介绍了 Spring MVC 3.2 中基于 Servlet 3 的新异步支持,并讨论了长时运行请求。第二个非常重要的异步处理动机是浏览器接收实时更新的需求。示例包括浏览器聊天、股票报价、状态更新、实时体育赛事结果等。诚然,并非所有示例对延迟的敏感度都一样,但它们都有相似的需求。

在标准的 HTTP 请求-响应语义中,浏览器发起请求,服务器发送响应,这意味着服务器在收到浏览器的请求之前无法发送新信息。已经出现了几种方法,包括传统轮询长轮询HTTP 流式传输,最近我们还有WebSocket协议。

传统轮询

浏览器不断发送请求以检查新信息,服务器每次都立即响应。这适用于可以在合理稀疏的时间间隔内进行轮询的场景。例如,邮件客户端可以每 10 分钟检查一次新邮件。它很简单,而且有效。然而,当新信息必须尽快显示时,这种方法变得效率低下,在这种情况下,轮询必须非常频繁。

长轮询

浏览器不断发送请求,但服务器在有新信息要发送之前不会响应。从客户端的角度来看,这与传统轮询相同。从服务器的角度来看,这与长时运行请求非常相似,并且可以使用第一部分中讨论的技术进行扩展。

响应可以保持打开多久?浏览器设置为 5 分钟超时,而代理等网络中间设备可能更早超时。因此,即使没有新信息到达,长轮询请求也应该定期完成,以允许浏览器发送新请求。这个IETF 文档建议使用 30 到 120 秒之间的超时值,但实际使用的值可能取决于您对分隔浏览器和服务器的网络中间设备的控制程度。

长轮询可以大大减少接收信息更新所需的请求数量,同时保持低延迟,尤其是在新信息以不规则的时间间隔可用时。然而,更新越频繁,它就越接近传统轮询。

HTTP 流式传输

浏览器向服务器发送请求,服务器在有信息要发送时响应。然而,与长轮询不同的是,服务器保持响应打开状态,并继续发送到达的更多更新。这种方法消除了轮询的需要,但它也更显著地偏离了典型的 HTTP 请求-响应语义。例如,客户端和服务器需要就如何解释响应流达成一致,以便客户端知道一个更新在哪里结束,另一个更新在哪里开始。此外,网络中间设备可能会缓存响应流,这会阻碍该方法的意图。这就是为什么长轮询在今天更常用的原因。

WebSocket 协议

浏览器向服务器发送 HTTP 请求以切换到 WebSocket 协议,服务器通过确认升级来响应。此后,浏览器和服务器可以通过 TCP 套接字双向发送数据帧。

WebSocket 协议旨在取代轮询的需要,并特别适用于需要高频在浏览器和服务器之间交换消息的场景。初始的 HTTP 握手确保 WebSocket 请求可以通过防火墙。然而,挑战也很显著,因为大多数已部署的浏览器不支持 WebSockets,并且在穿越网络中间设备方面存在进一步的问题

WebSockets 围绕文本或二进制消息的双向交换。它导致了一种与 RESTful、基于 HTTP 的架构截然不同的方法。实际上,在 WebSockets 之上还需要另一种协议,例如 XMPP、AMQP、STOMP 或其他协议,至于哪一个(或哪些)将占主导地位,还有待观察。

WebSocket 协议已由 IETF 标准化,而 WebSocket API 正在由 W3C 标准化最后阶段。已经出现了一些 Java 实现,包括 Jetty 和 Tomcat 等 servlet 容器。Servlet 3.1 规范可能会支持初始 WebSocket 升级请求,而单独的JSR-356将定义一个基于 Java 的 WebSocket API。

回到 Spring MVC 3.2,Servlet 3 异步功能可用于长时运行请求和 HTTP 流式传输,Filip Hanik 将这些技术称为“客户端 AJAX 调用的服务器版本”。至于 WebSockets,Spring 3.2 中还没有支持,但很可能会包含在 Spring 3.3 中。您可以关注SPR-9356以获取更新。

下一篇博文将转向示例代码,并更详细地解释新的 Spring MVC 3.2 功能。

Spring MVC 3.2 预览:介绍 Servlet 3 异步支持

工程 | Rossen Stoyanchev | 2012 年 5 月 7 日 | ...

最后更新于 2012 年 11 月 5 日 (Spring MVC 3.2 RC1)

概述

Spring MVC 3.2 引入了基于 Servlet 3 的异步请求处理。这是涵盖此新功能的多篇博文中的第一篇,并提供了理解如何以及为何使用它的背景。

早期发布的主要目的是寻求反馈。自 3.2 M1 版本发布以来,我们在这里和 JIRA 中收到了大量反馈。感谢所有尝试并发表评论的人!有无数的更改,还有时间接受更多反馈!

一览

从编程模型角度来看,新功能看似非常简单。控制器方法现在可以返回一个 java.util.concurrent.Callable 以异步完成处理。然后,Spring MVC 将在 TaskExecutor 的帮助下,在一个单独的线程中调用 Callable。这是一段之前的代码片段。


// Before
@RequestMapping(method=RequestMethod.POST)
public String processUpload(final MultipartFile file) {
    // ...
    return "someView";
}

// After
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

  return new Callable<String>() {
    public Object call() throws Exception {
      // ...
      return "someView";
    }
  };
}

控制器方法还可以返回一个 DeferredResult(Spring MVC 3.2 中的新类型)以在 Spring MVC 未知的线程中完成处理。例如,响应 JMS 或 AMQP 消息、Redis 通知等。这是另一段代码片段。


@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
  DeferredResult<String> deferredResult…

本周 Spring,2012 年 5 月 1 日

工程 | Josh Long | 2012 年 5 月 1 日 | ...

欢迎收看新一期《本周 Spring》!我正在 SpringOne 巡展 - 伦敦活动现场,在 Adrian Colyer 的精彩主题演讲的会场后排奋笔疾书。

  1. 大家是否错过了 Oleg Zhurakousky 的网络研讨会《Spring Integration 实战技巧》?不用担心,视频 在线提供

    另外,务必查看本周三(5 月 3 日)为 欧洲北美举办的第二部分!

    	</LI>
    	<LI> <a href = "http://blog.springsource.org/author/rclarkson/">Roy Clarkson</A> has announced the <a href = "http://www.springsource.org/spring-mobile/news/1.0.0.rc2-released">latest release of Spring Mobile</A>.  
    		 The release has several enhancements including more refined resolution, and improved site switching behavior. 
    		
    		</LI> 
    		<LI>  <a href = "http://blog.springsource.org/author/jbrisbin/">Jonathan Brisbin</A> just announced <a href="http://blog.springsource.org/author…

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有