当我们从Web Beans的公开草案过渡到建议最终草案时,我们真正希望做正确的一件事就是与Java EE平台的集成。到目前为止,我们作为EG所做的很多工作都集中在确定编程模型、Web Beans服务的语义和Web Bean管理器的行为。我们正在编写规范,假设Web Beans实现应该在不同的Java EE容器之间是可插拔的,因为这是Java EE社区中很多人认为EE平台应该发展的方向,并且我们希望Web Beans能够为其他规范如EJB、JTA甚至可能是Servlets(注意JPA和JSF已经支持这一点)指明道路。
自公开草案发布以来,我们的主要焦点已经转移到集成问题上。当草案被发送到EE平台专家小组并由Sun提出纳入Web Profile时,Web Beans引发了很多争议。这并不令人意外——Web Beans解决了一些很多人都有强烈意见的重要问题。我还与EE和EJB规范负责人以及EJB专家小组进行了许多技术讨论。出现了一些担忧,我们现在正在努力解决这些问题。
让我分享我对这些问题的看法,以及我们可能追求的一些方向。但首先...
...一些历史
在EJB 1.x和2.x的时代,人们普遍认为EJB的编程模型过于严格。规范给开发者带来了许多繁琐、分散和没有必要的要求。EJB 3.0改变了这一切。大多数令人烦恼的编码限制都被去除了。取而代之的是,EJB 3.0成为了第一个基于注解的Java组件模型。在JNDI查找的基础上,采用了一个简单的依赖注入模型,最终在EE 5平台级别被推广。我曾担任EJB 3.0专家组成员,并且为我们的成就感到自豪。
然而,Java EE 5的依赖注入模型从一开始就受到了批评。SpringSource的Rod Johnson等许多人认为,不支持非EJB Java类的注入是一个致命缺陷。(当时我不这么认为,但后来改变了想法。)另一方面,我对缺乏上下文生命周期模型感到不满——虽然,公平地说,当时包括Spring在内的一些其他DI解决方案也缺乏上下文模型。我还对JSF(基于XML的上下文)依赖注入模型与平台级别(基于注解的非上下文)模型的不匹配感到不满。这种不匹配使得将EJB组件与JSF集成变得困难。
EJB 3.0和JPA 1.0引入的大部分变化都经受住了时间的考验。EE 5的依赖注入模型却没有。上下文生命周期管理现在是依赖注入解决方案(包括Seam、Spring和Guice)的标准功能。最重要的是,Guice让我们认识到使用基于字符串的名称来标识API实现是多么的荒谬。Seam则展示了如何通过统一Web层和EJB层的依赖管理来简化应用开发。
Web Beans的启动是为了解决这些问题。最初的JSR提案抱怨说
-
EJB组件不了解Web层的请求、会话和应用程序上下文,也无法访问与这些上下文相关的状态。也不能将具有状态性EJB组件的生命周期范围限定在Web层上下文中。
-
JSF组件模型与Java EE不一致 ... 依赖注入 ...
JSR承诺要 统一
这两种组件模型,并使编程模型 大幅简化
。
需要一个全新的依赖注入模型:一个为事务性EE组件提供上下文生命周期管理的模型。
Web Beans是一个组件模型吗?
在Web Beans早期草案中,我们将Web Beans定义为组件模型。规范定义了两件事
- 一组Java类或EJB会话Bean必须满足的约束,以便成为Web Bean(主要但不限于必须明确指定@Component或其他部署类型),以及
- 随后可提供给Web Bean的服务。
我认为这是一个 统一 的组件模型:一个统一将解决自J2EE以来一直存在的问题——Java EE的Web层具有与事务层完全不同的组件模型(实际上,是多个组件模型)。它承诺要 打破
两个层之间的壁垒,使事务组件能够了解与Web请求相关的状态。它承诺为处理Web请求编排和负责数据访问(至少在JSF使用时)的组件提供真正的统一编程模型。
结果证明这是错误的方法。来自EE小组的强烈反馈是Web Beans不应该定义一个新的组件模型。来自Sun的EE规范领导人的反馈是Web Beans定义的服务应该对所有类型的Java EE组件可用——而不仅仅是那些符合我们定义的 Web Bean
的。
在Sun的敦促下,我们对规范进行了两项更改。首先是主要语言上的改变。我们将Web Beans重新定位为一系列服务,由一个管理者类似于JTA的TransactionManager提供,而不是一个具有容器的《组件模型》。但这同时也意味着另外两个技术上的改变
- 我们大大放宽了对哪些对象是Web Beans的限制,使得每个EJB会话bean和每个JavaBean现在都是Web Bean,无需进行显式声明,并且
- 我们提供了一套SPI,允许那些不是JavaBeans或EJB会话bean的对象利用Web Bean管理器提供的服务。
特别是,我们为Servlets和消息驱动的bean(本质上不是可注入的对象)提供了注入,并允许其他EE技术和第三方框架将他们的组件提供给Web Beans进行注入,并利用Web Beans服务。
这无疑是正确的做法,Web Beans规范现在更强大且侵入性更低。它仍然承诺提供更统一的编程模型,但这些改变的一个副作用是模型变得更普遍有用,而不再是针对JSF和EJB的特定解决方案。这种情况并非第一次发生:EJB 3.0专家组也产生了一些技术(JPA、EE 5依赖注入),最终应用得比最初设想的更广泛。
Web Beans 仍然是组件模型吗?
不幸的是,有些人仍然不满意。平台专家组的许多成员认为,简单Web Bean的概念仍然指定了一种新的组件模型。那么,简单Web Bean究竟是什么,为什么我们需要它们呢?
简单Web Bean并不是什么新鲜事物。它只是一个Java类。你已经编写了数百甚至数千个简单Web Bean。每个JavaBean都是一个简单Web Bean。我们试图做到的是,允许那些没有特定编写为EJB的对象可以被注入并利用Web Beans服务。
简单Web Bean相对于EJB会话bean有以下优势
- 不需要使用组件定义注解或XML显式声明为EJB
- 其接口不需要使用@Local或@LocalBean
- 它可以是final的,或者有final方法
- 它有一个更
自然
的生命周期和并发模型——Java类的正常生命周期,而不是EJB定义的增强
生命周期/并发语义 - 如果它是一个有状态的对象,它不需要一个@Remove方法
- 它可以利用构造函数注入
你可以使用现有的JavaBeans和许多其他Java类作为简单Web Bean。作为副作用,简单Web Bean减少了新Java EE用户的心理差距
——他们可能会因为不熟悉的EJB语义而感到害怕——以及相当痛苦的显式指定业务接口和添加空@Remove方法——并让这些新用户更容易地开始使用容器管理的对象。
另一方面,与会话bean不同,根据目前对简单Web Bean的定义
- 没有方法级事务划分或安全
- 不能有超时或异步方法
- 不能有远程接口或作为web服务端点
- 没有容器管理的并发(锁)
- 不支持实例级别的钝化或池化
因此,在我看来(这是当前和以前的EJB规范领导的共同观点),简单Web Bean并不与EJB竞争作为应用程序事务层的解决方案。事实上,简单Web Bean并不是什么新东西——Java EE开发者已经在使用EJBs和JavaBeans并行。Web Beans只是让他们的生活变得更容易。
但是有些人不同意。例如,一位专家担心,通过提供一种称为“简单”Web Bean的东西,我们在鼓励人们使用它们而不是EJB。风险是开发者可能会被引导不使用“非简单”EJB。这在EE组中已经成为一个真正的难题,并威胁到整个Web Beans工作的进展。
当然,我们正在努力解决这个问题。一种可能性是将简单Web Bean的定义移至EJB规范中,作为新的EJB组件类型。另一种可能性是简单地从规范中删除简单Web Bean,并要求每个人都将所有对象编写为EJB。
我个人无法想象发布不支持JavaBeans的依赖注入解决方案的Java EE 6。所有其他解决方案都支持JavaBeans和EJB。EE 5错过了这艘船 - 我不希望EE 6重蹈覆辙。我认为这是一个用户希望决定何时使用EJB的情况。他们不希望我们强迫他们做出决定。
其他EE资源类型的注入
EE专家提出的第二个问题是,Web Beans规范目前没有定义对各种Java EE资源类型的注入支持。具体来说,Web Beans没有明确定义对JDBC数据源、连接、Web服务端点、远程EJB或持久性上下文的注入。当然,你仍然可以使用现有的Java EE 5@Resource和@PersistenceContext注解来注入Java EE资源,但这样你将错过Web Beans定义的更灵活和更类型安全的模型的优点。
事实上,只要Java EE容器在初始化时调用适当的Web Beans SPI,Web Beans就支持EE资源的注入(或任何其他事物)。但EE规范和Web Beans规范都没有要求这样做。所以这是一个应该容易解决的问题。
可插拔性
我们投入了大量精力来定义EE容器和Web Bean管理器之间的交互,目的是支持可插拔的Web Bean管理器。然而,目前定义的任何内容都没有对EE容器提出任何新的要求。遗憾的是,目前规范中仍存在一些只能通过以下方式解决的问题:
- 放弃对可插拔性的要求或
- 对EE容器提出新的要求。
(如果您想了解将施加于Java EE容器的确切新要求,请搜索公共草案中的“开放问题”)
这两条路径在技术上都是可行的,但其中一条需要更多的工作,并且需要在各个专家小组之间进行更多的协调,其中一些小组已经努力应对紧张的截止日期。如果Java EE 6需要Web Beans,那么可插拔性是否真正对用户有很大的价值还不清楚。是否有人真的需要更换他们的Web Bean管理器?
我很乐意听到社区对可插拔性是否真正值得追求的看法。
包和命名
很多人讨厌“Web Beans”这个名字,他们认为这个名字掩盖了我们定义的模型的普遍性。我认为这个名字更像是一个吸引人的品牌,而不是定义Web Beans做什么。想想微软和“.net”。我不介意改变名字,但还没有人提出一个很好的替代方案。一方面,我讨厌首字母缩略词,像“Java Dependency Injection”这样的描述性名称并不能真正捕捉到Web Beans所做的一切。
独立于这个反对意见,很多人认为,将我们的注解按关注点打包,而不是将它们全部放在javax.webbeans例如,以下包布局可能更有意义
- javax.dependency- 与DI相关的注解:绑定类型、部署类型,@Initializer, @Produces等。
- javax.contexts- 与作用域相关的注解,Context接口
- javax.interceptor(已存在)- 与拦截器和装饰器相关的注解
- javax.events - @Observes,事件总线接口
我认为重新打包是一个非常好的主意。
好消息
好消息是,关于(受Guice和Seam启发的)Web Beans中依赖注入模型的实际技术细节的争论很少。我从规范审查员那里得到的反馈是一致的积极。这让我对更多更政治
的问题也能得到解决充满信心。
你认为呢?
我在这篇文章中讨论的问题对于Java EE社区的每个成员以及Java EE平台未来的方向都很重要。我不相信我们应该在用户不参与的情况下“闭门造车
”,请发言并告诉我们你想让我们做什么。并且请花时间了解更多关于Web Beans的信息。