个人简介 Juergen Hoeller是Spring框架的联合创始人,自2003年2月Rod的Interface21将Spring框架开源起,他就是最活跃的Spring开发者。Juergen是一名经验丰富的咨询师,擅长于Web应用、事务管理、O/R映射技术以及轻量级远程调用。
QCon是一个由社区组织、服务于社区的大会。因为投入了大量的精力,力争能让社区中的领头人就最重要的话题分享最精彩的内容,所以大会拥有高质量的会议体验。QCon的初衷就是要有一定的技术含量,关注企业应用,符合技术团队领导者、架构师与项目经理的需求。
1. 我是Charles Humble,在我身边的是Juergen Hoeller,Spring Framework的项目负责人。Juergen,我想先从Spring 3.1的一些特性开始这次采访。你能跟我们谈谈Spring Cache吗?
缓存肯定是Spring 3.1中的主要特性,它有点历史,其实这算是一个长期的需求了。我们从很早之前就想做一个缓存抽象了,终于在Spring 3.1里找到了这个机会真正发布它。Spring Cache的想法并非简单地为缓存提供方做一个抽象,它更多地是和访问模式有关,应用程序与缓存的典型交互是通过一个Spring抽象来完成的,其中提供了缓存管理器与缓存抽象、典型布局、(支持)键值对、缓存区等等概念。我们不仅仅提供抽象,还有声明式缓存,提供了注解和拦截机制。我们称其为缓存注解驱动,这和用于事务的TX注解驱动有点类似,你调用了一个方法,框架会拦截调用,检查缓存中是否有值,如果有则获取该值,而非调用方法,这些都是基于注解的,因此是一种注解驱动模型。
这才是我们真正想要的,缓存抽象是这些访问机制背后的东西。SPI的实际实现中只会自带Ehcache,作为参考实现;我们也依赖了一些外部项目,需要运行它们,因此为商业缓存提供方做了一些适配器,它们大多是商业软件。
我们引入缓存的部分原因是因为分布式缓存又一次成为了热门话题。当然,这并非是一个新兴领域,但随着云运动、云平台、平台即服务(Platforms as a Service)、分布式缓存再度成为话题。类似GemFire、Coherence这样的产品是我们所提供的模型的理想后端。而且我们以某种方式提供了这些产品的适配器,但不包含在Spring Framework项目本身里面。
2. 它是怎么与Spring Data搭配使用的?我想两者之间一定有一些重叠的地方,是吗?
是的,有关系那是很正常的事,因为它们都是针对同一领域的东西。缓存提供方某种形式上也被用作数据存储,特别是如今的分布式缓存为我们提供了持久化存储。Spring Data的目标是与更多不同的数据存储进行交互,比如Redis和MongoDB,我们为这类数据存储提供了Spring模板风格的访问类。因此,从某种形式上来说,两者是有关系的,但技术上又有不同,Spring Data所支持的更多是和数据库相似的访问模式,从用例上来说,如果更多地是在讨论面向缓存的数据访问模式,那么这时说的就是缓存抽象了。当然,还有很多其他的数据存储,它们不用键值模型,比如Neo4J,这是一个图数据库。
与这些数据源交互的方式有好几种。Spring Data并不是一个真正的抽象,它是一个针对那些数据存储的不同访问模型的支持包的集合。并非真的试图去抽象它们,而是试着把它们原生地暴露给基于Spring的应用程序。
3. 被搁置了很久的JCache JSR又被端了出来,有可能会被重新提上议程,这对Spring Cache会有影响吗?
是的;JCache JSR是我们所遵循的东西。某种程度上来说,我们正是在等它。但是目前我们只能说它在Spring 3.1里,还不是EE6的一部分。现在它还没有深入缓存领域,因此我们只能暂时自己提供缓存抽象,看起来实际是我们在提供完善的长期产品,就算JSR 107有了进展,那也很可能是在重复发明轮子。我并不认为老的JSR正在延着旧方向发展;它可能会成为EE7的一部分,提供新的缓存方法,我们会保证在我们的缓存抽象上一切都能完美集成,在缓存抽象之后的东西可能更重要一些,就像我们在其他领域做的那样。
我们将保证能很好地进行适配,在缓存方面我并没看到什么阻碍,因为从访问模式角度来看缓存还是很好理解的。我希望当JSR来临时,一切能自然地匹配起来;这可能是Spring 3.3要考虑的了。
4. 3.1中有没有关注过Spring Batch?
在引入新的核心功能时,我个人总是会考虑Spring Batch,因为Spring Batch对Spring有特殊的用法,传统的基于Spring的Web应用程序可能并不会这么用。Spring中的任务执行器、任务调度器,所有的并发编程设施,针对Fork/Join框架等内容,其中的一些东西在Java 7中将得到扩展或某种程度的改造。对于这些东西,我们计划以某种形式来暴露它们,或在Spring Batch中加以利用,这是我目前的主要考虑。
我认为Spring Batch模型、编程配置模型都是很好理解和被广泛接受的。我看到很多潜在的可能,尤其是在Spring Batch里,可以充分利用Fork/Join这样的东西,暴露它,把自己的步骤模型转换过去。这是我们通常建立的关系。Spring Framework提供了核心功能,已经有了一些用例,一些其他的Spring项目,例如Spring Integration和Spring Batch,使用这些功能;把它们集成进来。我希望基于Spring 3.1的Spring Integration和Spring Batch的版本能在Spring Framework 3.1发布后早日问世。
5. 刚才你提到了Fork/Join,就Spring来说,对Java 7里其他的特性有感兴趣的么?
有不少,我觉得Fork/Join可能是最重要的,它带来的影响最大,因为它是种编程模型、用户级功能,人们要去改造、重新考虑他们实现自己算法的方式。还有些其他东西,例如try-with-resources类和autocloseable接口。我们正在考虑使用这些东西,或者是以某种形式针对一些Spring类暴露它们,这样就能提供可以同try-with-resources类协作的框架类了。还有些别的正在考虑中的东西,比如JDBC 4.1,但那不是主要的,我们会保证我们的JDBC适配器(我们提供的JDBC装饰器)能用于JDBC 4.1。因此我们将做一次全面的Java 7升级,就我的使用经验来看,我相信Fork/Join框架和try-with-resources会是用户关注的东西。
还有一个我很想在Java 7中看到的东西,就是日期/时间API,不幸的是它并没有正式出现在Java 7中。我希望它能包含在Java 8里,同时再提供一个独立的版本,因为这真是个好东西;Java.util.Date和相关的代码需要有人关爱,需要一些竞争,需要一些改造,而日期/时间API就是一个好的开端。一旦它发布了,我们会立即把它纳入Spring的编程模型中,就好比Bean Validation和JSR 303(这是同一类东西);我们立刻就支持它了。 暂时我们还是不得不绑上Joda-Time,即使是在Java 7上。
6. 你们还增加了对话(conversation)支持,我猜这和CDI或Seam很类似。在Spring里我可以在什么地方使用它呢?
对话,从历史上来看,是与Web Flow相关联的。因此,我们当然在Spring Web Flow里有导航模型和与之相关的对话模型,基本是由流程导航模型强势驱动的,我们在Spring 3.1中增加对话的部分原因就是为了简化Web Flow:相比可能的实际代码要有更多的动机。其他的一些影响来自JSF,JSF里有多个对话扩展:例如MyFaces Orchestra;还有一些不这么有名的;当然还有CDI里的那个,也是面向JSF的。我们尝试在这个领域里提供一些公用的东西,所以说Spring 3.1并不是要深入Web Flow领域,而是想提供基础对话管理机制,Web Flow可能会用到它,可能会代理给它,不仅仅是一个基础的对话存储抽象,有当前对话的概念,并进行管理。
就我们目前所理解到的东西,这就是我们真正需要提供的一切了,有了它我们就能有一定的互操作性,一个Web Flow管理的对话可能会与JSF对话或在Spring MVC中使用的对话的互操作性。从用例来看,会有Web Flow,会有JSF对话(这是很好理解的),从Spring MVC的视角来看,我们有一个会话属性存储机制,管理Spring MVC中的会话属性,我们还想以某种形式将它和更灵活的对话管理方案集成起来。我们目前正在着手进行定稿。
最重要的用例是人们希望做到窗口隔离。对Spring MVC而言,这可能是该领域中最大的一个要求或请求。会话属性默认是存储在HTTP会话中的,这就意味着所有窗口、所有标签页都在同一个浏览器存储中,基本就是与同一个会话交互。如果你在多个标签页中打开了同一个表单,它们都会共享相同的会话属性,它们会把自己的数据存储到里面。因此,针对多个独立的表单对话,在多个窗口标签页里要有一层隔离,那是Spring MVC用户发起的一个请求,而且这也是我们日程中的一部分,即试图针对这个特别的问题提供一流解决方案。所以说,真的是这么多东西凑在一起形成了Spring 3.1里的对话管理功能。
这有点像CDI和Seam里的对话,但仅限于三个视角中的一个。MVC视角和Web Flow视角非常独立,从很多方面来看都有很多不同之处。所以我们会发现,我们的任务是去发现并标识出公共的部分,把它纳入Spring的核心中来。
7. 既然你提到了CDI,你对它有什么看法?
我一直在密切关注CDI规范的发展,它的历史很有意思。它开始时和我们最终得到的东西很不一样,它原来的目标是开发一个对话作用域(conversation scope),最原始的任务是开发一个介于JSF和EJB3之间的对话域,全局JSF-EJB3集成也是其中之一。但最终它却变成了一个相当丰富的依赖注入模型。其中不乏有趣的想法,有一些和Spring中的做法不太一样,尤其是Spring 2.5的。当然,这里也有一些公共的东西,Spring 3.0和3.1同时都支持JSR 330定义的公共依赖注入注解,CDI容器也支持这套注解:@inject、@qualifier、提供方接口,还有依赖注入模型的核心部分。
当然,在此之上CDI还添加了一些东西:事件模型、一个特殊的作用域模型(soping model)。从设计上来说其中有些东西与Spring不同,但我要说的是如果你对Spring、依赖注入和Bean作用域有比较深入的理解,这些东西都能被很好地转换到CDI上,反之亦然。因此在两者间迁移应该不会太困难。它们只是选择了不同的设计方向,很自然地涉及了一些不同的设计权衡。我也有一些不太认同CDI的地方,但我肯定CDI的设计者对Srping的一些设计也不太认同,所以我觉得这很正常。尽管我们我们关注CDI,但目前还没有进一步的计划。
我们正紧跟JSR 330的发展,看起来针对Java EE7会有一个核心依赖注入规范的版本,起码是1.1版,大家可以期待Spring提供一个支持该版本的实现。
8. 我想Java EE6与Spring 3几乎是同时发布。
只是相差几天而已。
9. 那个标准对Spring有什么影响,Spring又是如何兼容它的?
我们关注的不仅仅是CDI,而是整个Java EE 6规范,在Java EE6规范发布后的几天里Spring 3.0就发布了GA版本并不是一个巧合。我们密切关注着几个规范的演进,其中包括JPA 2.0、JSF 2.0,当然还有JSR 330和JSR 303(Bean Validation Specification)。就Spring而言,这四个东西是EE6里最有趣的部分,它们实际上非常独立。我是说JSR 303有独立的实现,可以很好地放入各种应用程序中,JSR 330依赖注入注解也是如此,JPA 2.0 Provider在很多环境里也很有用。这就是我们关心它们,并在这些规范定稿后(实际上是在它们发布生产质量的参考实现之前)就立刻支持它们的部分原因。
EE6里的其他部分,例如Servlet 3.0,我们只是测了一下,还没有专门去支持它们。在Spring 3.1中我们正在缩小与EE6的差距,Servlet 3.0支持是其特性之一,尤其是会支持Servlet 3.0的配置模型。这是一种在Servlet 3.0中替代web.xml驱动启动(Servlet容器初始化模型)的方式,它和Spring的基于Java的配置模型搭配起来非常合适。因此,我们正尝试为结合使用Spring 3.1的Servlet 3.0用户提供无缝体验,基本是非XML配置的体验,这真的是一个很好的组合。除此之外,Java EE6里还有JAX-RS和一些其他的有趣的规范,尽管Spring本身并没有特别去支持JAX-RS,但它们却能很好地与Spring协同使用。
原因很简单:所有主流的JAX-RS提供方都自己提供了Spring支持。因此,你将会有Jersey的Spring支持,有RESTEasy的Spring支持。要在JAX-RS世界里做一个好公民,在Spring Framework方面并没什么要做的。所以我说Spring 3.x有很好的Java EE6背景,不仅独立使用了多个EE6的规范,还能在Java EE6服务器上运行完整的Spring应用程序,就Spring而言这相当于默认把所有的规范和一些提供方打了个包。你有了一个JPA 2.0提供方、一个JSR 303提供方以及一个Servlet 3.0容器。
这是一个很好的基础,Spring 3编程模型可以构建在此基础之上。我们就是这么认为的,以GlassFish为例,GlassFish 3.0、3.1对基于Spring的应用程序而言是个很棒的服务器,我们正是用它来做测试的。我们甚至还有专门的GlassFish加载时织入支持(GlassFish load time support),它真的很适合基于Spring的应用程序。
10. 大家都在讨论Java EE7中的一个东西,即多租户(multi-tenancy)问题,在多个不同环境(可以是一台App Server,或者是一个私有云,或者是公有云)上运行同一个应用程序,Spring中是否有这个问题?
在我们的理解中,EE7规范会处理多租户,在我看来,Java EE世界里的应用程序之间本身就有很好的隔离,云平台(比如我们目前拥有的Platforms as a Service:Google App Engine、Amazon Elastic BeanStalk)上也是如此;它们使用的war部署单元,基本都是在运行时围绕war文件管理着一个独立的容器,这看上去已经把它们隔得很开了。就这点来说,基于Spring的应用程序在war文件里真的可以看成是高级公民了。从多个方面来看,Spring是基于war部署当仁不让的选择,认识到了这一点之后,我们就没什么必要参与到任何Servlet容器会提供的隔离模型中去了。
如果有什么事是我们可以做的,那么我们一定会做的,例如应用程序可能会为容器提供一些配置上下文,用于标识与其他应用程序的某类隔离级别。不过Java EE 7规范先要在这方面发布一份更详细的模型。
11. 在我的印象中,Spring不太愿意参与标准化过程。通常你们是遵循标准,甚至是紧跟标准,但我却没看到Spring在标准化过程中有多少投入。不知道我这么说是否合理?
有这样一个印象也是很正常的,尽管在历史上和JCP内部,事情其实并非如此。从具体参与的角度来说,我们的确参与了JSR 330。虽然JSR 330主要是由Bob Lee驱动的,与Bob Lee一起,我们也是该规范的合作领导者,但严格说来,Bob Lee是主要领导。我们还在关注几个其他的规范,关注专家组里的成员,比方说JSF 2.0。我想我们在设计影响力上可能比不上其他人,因为JSF也有几个领导者,他们在推动规范向前发展,专家组里的大多数人会听从他们的意见;JSF 2.1和2.2的情况也差不多。我们正在积极参与其中,讨论以何种方式为JSF 2.2做些具体的工作。
但以我来看,我们要在他们开发时就遵循规范,从早期阶段就开始关注规范。我们并不是非要去影响他们;我们只要确保这些东西和Spring的编程模型放一起能玩得转就可以了。这才是我们最重要的任务。在一些特定的领域里,我个人很关心标准化:约束注解(constraint annotations),我觉得它们真的是深入到了领域模型的核心之中,这些东西应该被标准化;依赖注入,采用增加注入(inject)和限定词(qualifier)的形式,这很适合标准化。如果让我来选择典型(stereotype)模型,好比Spring中添加了组件和自定义典型,如果JSR 330或JSR 250有一个灵活的核心典型模型方案,我会立刻使用它们的。
我个人在标准化方面对一些更具体的东西很感兴趣,但总的来说,Spring提供了自己的编程模型和配置模型,可以自给自足。因此Spring可以选择性地增加标准化的部分,但我认为它自身不应该标准化。它更应该成为所有这些围绕它的标准的好公民,成为各标准化部件之间的粘合剂。这才是目前的Spring,这才是它的定位。
12. 你有Spring 3.1和Spring 3.2的时间表吗?
大致的日期是有的;对于Spring 3.1来说有确切的日期。我们正在努力开发milestone 2版本,就计划了两个里程碑版本,然后就是RC1,milestone 2是4月发布,RC1是5月底,GA是在6月底。我希望我们能按着这个计划进行,这不仅取决于我们,一旦发布了RC版本,就是由用户社区来告诉我们在GA前是否需要更多的RC版本。因此说Spring 3.1大致会在Q2底发布,Spring 3.2会紧随其后,基本是2012年年初。这个动作比我们以前发布主要版本快多了。Java 7会在今年Q3发布,Spring 3.2受Java 7的影响很大,因为其中的主要特性就是Java 7支持。所以什么时候我们觉得从Spring方面来看Java 7的任务完成了,那就是我们发布Spring 3.2的时候。我觉得明年早些时候的机会会更好些。
我们也已经有了一些Java 8的想法。Java 7和Java 8被分开了。Java 8中有些东西是没来得及放入Java 7的,Java 8语言特性中的的许多设计已经很清楚了,基本是由JDK团队提交具体的提案,比如闭包会基于他们所谓的单一抽象方法类型来进行编译。所以我们已经把一些可能的设计影响和设计考虑纳入了Spring 3.1和3.2,基本已经做好了迎接Java 8语言增强的准备。这些都是超前的,因为在2012年底前Java 8都不会发布,也许2013年初会更实际一些;我们就是在为此做准备。这就是我们目前的计划。我很确定Spring 3.3最终会在Java EE 7、Java 8问世后不久发布。
通常我们只会提前12个月做具体计划。在Java领域中,Java行业的发展是非常快的,因此很难说哪些是要在一年里做考虑的。我们在发布计划上很灵活、很敏捷。我们真的是在倾听,大家告诉我们要发布什么,我们就力争在正确的时间发布它们,并不一定总要在规范定稿的时候,正确的时间通常是指大家开始采用某些规范的时候,他们真的开始使用某些参考实现的时候。Java 7的时机很好,大家实际会很快使用它。以Tomcat为例,让Tomcat 7运行在OpenJDK 7上就是一种很直接的从OpenJDK 6迁移过来的办法。因此我希望Java领域中至少有部分东西能很快升级到Java 7上。
这就是为什么我们会很快发布一个带Java 7支持的Spring 3.2版本,因为我们希望其被采用的过程至少能比以前好。你知道的,Java 5和Java 6花了好多年才在业内真的使用起来。我真心希望Java 7能很快成为主流。