Java EE 8愿望清单:缺少这些,Java EE将不会完美
英文原文:Java EE 8 wish list
Java EE 7 已于 6 月中旬正式发布,新版本提供了一个强大、完整、全面的堆栈来帮助开发者构建企业和 Web 应用程序——为构建 HTML5 动态可伸缩应用程序提供了支持,并新增大量规范和特性来提高开发人员的生产力以及满足企业最苛刻的需求。
下面的这个图表包含了 Java EE 7 中的各种组件。橙色部分为 Java EE 中新添加的组件。
尽管新的平台包含了诸多新的特性,但是开发者对此似乎并不满足,尽管他们中的大部分还没有迁移到 Java EE 7(或许是由于 Java EE 7 的特性还不完善),但是这并不影响他们对于 Java EE 8 特性的设想。
比如,在 Java EE 6 发布(2009 年 12 月 10 日发布)后,开发者 Antonio Goncalves 认为该版本并没有解决一些问题,因此写了一个希望在 Java EE 7 中包含的特性清单。有趣的是,他写的 4 个特性中,其中有 2 个(flows 和 batch)已经包含在 Java EE 7 中了,而第 3 个特性(caching)原本也计划包含其中,但由于开发进度关系,在 Java EE 7 最终发布前被舍弃。
此举促使开发者 Arjan Tijms 也写了一个他希望在 Java EE 8 中出现的特性清单,如下。
- 无处不在的 CDI(Contexts and Dependency Injection for Java EE,上下文与依赖注入)
- 更深入的 Pruning(修剪)和 Deprecating(弃用)
- 一个标准的缓存 API
- administrative objects(管理对象)的应用内替代品
- 综合的现代化的安全框架
- 平台范围内的配置
下面就来详细阐述这些特性的必要性。
1. 无处不在的 CDI
实际上这意味着 2 种不同的东西:使 CDI 可以用在目前不能用的其他地方、基于 CDI 来实现和改造其他规范中的相关技术。
a. 使 CDI 可以用在其他地方
与 Java EE 6 相比,Java EE 7 中的 CDI 的适用范围已经扩大了很多,比如 CDI 注入现在可以工作在大多数 JSF 组件(artifacts)中,比如基于 bean validation 的约束验证器。不幸的是,只是大部分 JSF 组件,并非所有的,比如转换器和验证器就不行,尽管 OmniFaces 1.6 将支持这些特性,但最好是在 Java EE 7 中能够开箱即用。
此外,Java EE 7 中的 CDI 也没有考虑到 JASPIC 组件,在此之中注入操作将无法工作。即使 http 请求和会话在 Servlet Profile SAM 中可用,但是当 SAM 被调用时,相应的 CDI 作用域也不会被建立。这意味着它甚至不能通过 bean 管理器以编程方式来检索请求或会话 bean 作用域。
还有一种特殊情况是,各种各样的平台 artifacts 可以通过一些替代的注解(如@PersistenceUnit)来注入,但早期的注入注解(@Resource)仍然需要做很多事情,比如 DataSource。即使 Java EE 7 中引入了 artifacts(如任务调度服务),但也不得不通过“古老”的@Resource 来注入,而不是通过@Inject。
b. 基于 CDI 来实现和改造其他规范中的相关技术
CDI 绝对不应该只专注于在其他规范中已经解决的那些问题,其他规范还可以在 CDI 之上来实现它们各自的功能,这意味着它们可以作为 CDI 扩展。以 Java EE 7 中的 JSF 2.2 为例,该规范中的兼容 CDI 的视图作用域可作为 CDI 扩展来使用,并且其新的 flow 作用域也可被立即实现为 CDI 扩展。
此外,JTA 1.2 现在也提供了一个 CDI 扩展,其可以声明式地应用到 CDI 托管的 bean 中。此前 EJB 也提供了类似的功能,其背后技术也使用到了 JTA,但是声明部分还是基于 EJB 规范。在这种情况下,可以通过 JTA 来直接处理其自身的声明性事务,但是这需要在 CDI 之上进行。
尽管从 EJB 3 版本开始,EJB beans 已经非常简单易用了,同时还相当强大,但问题是:CDI 中已经提供了组件模型,EJB beans 只是另一个替代品。无论各种 EJB bean 类型有多么实用,但是一个平台上有 2 个组件模型,容易让用户甚至是规范实现者混淆。通过 CDI 组件模型,你可以选择需要的功能,或者混合使用,并且每个注解提供了额外的功能。而 EJB 是一个“一体”模式,在一个单一的注解中定义了特定的 bean 类型,它们之间可以很好地协同工作。你可以禁用部分不想使用的功能。例如,你可以关闭 bean 类型中提供的事务支持,或者禁用@Stateful beans 中的 passivation,或者禁用@Singleton beans 中的容器管理锁。
如果 EJB 被当做 CDI 的一组扩展来进行改造,可能最终会更好。这样就会只有一个组件模型,并且具有同样有效的功能。
这意味着 EJB 的服务,如计时器服务(@Schedule、@TimeOut)、@Asynchronous、 @Lock、@Startup/@DependsOn 和@RolesAllowed 都应该能与 CDI 托管的 bean 一起工作。此外,现有 EJB bean 类型提供的隐式功能也应该被分解成可单独使用的功能。比如可以通过@Pooled 来模拟@Stateless beans 提供的容器池,通过@CallScoped 来模拟调用@Stateless bean 到不同的实例中的行为。
2. 更深入的 Pruning(修剪)和 Deprecating(弃用)
在 Java EE 平台中,为数众多的 API 可能会令初学者不知所措,这也是导致 Java EE 如此复杂的一个重要原因。因此从 Java EE 6 版本开始就引入了 Pruning(修剪)和 Deprecating(弃用)过程。在 Java EE 7 中,更多的技术和 API 成为了可选项,这意味着开发者如果需要,还可以包含进来。
比如我个人最喜欢的是 JSF 本地托管 bean 设施、JSP 视图处理程序(这早在 2009 年就被弃用了),以及 JSF 中各种各样的功能,这些功能在规范文件中很长一段时间一直被描述为“被弃用”。
如果 EJB 组件模型也被修剪将会更好,但这有可能还为时过早。其实最应该做的是继续去修剪 EJB 2 编程模型相关的所有东西,比如在 Java EE 7 中依然存在的 home 接口。
3. 一个标准化的缓存 API
JCache 缓存 API 原本将包含在 Java EE 7 中,但不幸的是,该 API 错过了重要的公共审查的最后期限,导致其没能成为 Java EE 7 的一部分。
如果该规范能够在 Java EE 8 计划表的早期阶段完成,就有可能成为 Java EE 8 的一部分。这样,其他一些规范(如 JPA)也能够在 JCache 之上重新构建自己的缓存 API。
4. 所有管理对象(administrative objects)的应用内替代品
Java EE 中有一个概念叫“管理对象(administrative objects)”。这是一个配置在 AS 端而不是在应用程序本身中的资源。这个概念是有争议的。
对于在应用服务器上运行许多外部程序的大企业而言,这可以是一个大的优势——你通常不会想去打开一个外部获得的应用程序来改变它连接的数据库的 相关细节。在传统企业中,如果在开发人员和操作之间有一个强大的分离机制,这个概念也是有益的——这可以在系统安装时分别设置。
但是,这对于在自己的应用服务器部署内部开发的应用程序的敏捷团队来说,这种分离方式是一个很大的障碍,不会带来任何帮助。同样,对于初学者、教育方面的应用或者云部署来说,这种设置也是非常不可取的。
从 Java EE 6 的@DataSourceDefinition 开始,许多资源(早期的“管理对象”)只能从应用程序内部被定义,比如 JMS Destinations、email 会话等。不幸的是,这并不适用于所有的管理对象。
不过,Java EE 7 中新的 Concurrency Utils for Java EE 规范中有明确的选项使得它的资源只针对管理对象。如果在 Java EE 8 中,允许以一个便携的方式从应用程序内部配置,那么这将是非常棒的。更进一步来说,如果 Java EE 8 中能够定义一种规范来明确禁止资源只能被 administrative,那么会更好。
5. 综合的现代化的安全框架
在 Java EE 中,安全一直是一个棘手的问题。缺乏整体和全面的安全框架是 Java EE 的主要缺点之一,尤其是在讨论或评估竞争框架(如 Spring)时,这些问题会被更多地提及。
并不是 Java EE 没有关于安全方面的规定。事实上,它有一整套选项,比如 JAAS、JASPIC、JACC、部分的 Servlet 安全方面的规范、部分 EJB 规范、JAX-RS 自己的 API,甚至 JCA 也有一些自己的安全规定。但是,这方面存在相当多的问题。
首先,安全标准被分布在这么多规范中,且并不是所有这些规范都可以用在 Java EE Web Profile 中,这也导致难以推出一个综合的 Java EE 安全框架。
第二,各种安全 API 已经相当长一段时间没有被现代化,尤其是 JASPIC 和 JACC。长期以来,这些 API 只是修复了一些小的重要的问题,从来没有一个 API 像 JMS 2一样被完整地现代化。比如,JASPIC 现在仍然针对 Java SE 1.4。
第三,个别安全 API,如 JAAS、JASPIC 和 JACC,都是比较抽象和低层次的。虽然这为供应商提供了很大的灵活性,但是它们不适合普通的应用程序开发者。
第四,最重要的问题是,Java EE 中的安全机制也遭遇到了“管理对象”中同样的问题。很长一段时间,所谓的 Java EE 声明式安全模型主要认证过程是在 AS 端按照供应商特定方式来单独配置和实现的,这再次让安全设置对于敏捷团队、教育工作者和初学者来说成为一件困难的事。
以上这些是主要的问题。虽然其中一些问题可以在最近的 Java EE 升级中通过增加小功能和修复问题来解决。然而,我的愿望是,能够在 Java EE 8 中,通过一个综合的和现代化的安全框架(尽可能地构建在现有安全基础上)将这些问题解决得更加彻底。
6. 平台范围内的配置
Java EE 应用程序可以使用部署描述文件(比如 web.xml)进行配置,但该方法对于不同的开发阶段(如 DEV、BETA、LIVE 等)来说是比较痛苦的。针对这些阶段配置 Java EE 应用程序的传统的方法是通过驻留在一个特定服务器实例中的“管理对象”来实现。在该方法中,配置的是服务器,而不是应用程序。由于不同阶段会对应不同的服 务器,因此这些设置也会随之自动改变。
这种方法有一些问题。首先在 AS 端的配置资源是服务器特定的,这些资源可以被标准化,但是它们的配置肯定没有被标准化。这对于初学者来说,在即将发布的应用程序中进行解释说明比较困难。对于小型开发团队和敏捷开发团队而言,也增加了不必要的困难。
对于配置 Java EE 应用程序,目前有很多可替代的方式,比如在部署描述符内使用(基于表达式语言的)占位符,并使部署描述符(或 fragments)可切换。许多规范已经允许指定外部的部署描述符(如 web.xml 中可以指定外部的 faces-config.xml 文件,persistence.xml 中可以指定外部的 orm.xml 文件),但是没有一个统一的机制来针对描述符做这些事情,并且没有办法去参数化这些包含的外部文件。
如果 Java EE 8 能够以一种彻底的、统一平台的方式来解决这些配置问题,将再好不过了。似乎 Java EE 8 开发团队正在计划做这样的事情。这将会非常有趣,接下来就看如何发展了。
结论
Java EE 8 目前尚处于规划初期,但愿上面提到的大多数特性能够以某种方式加以解决。可能“无处不在的 CDI”的几率会大一些,此方面似乎已经得到了很大的支持,且事情已经在朝着这个方向发展了。
标准化缓存 API 也非常有可能,它几乎快被包含在 Java EE 7 中了,但愿其不会再次错过规范审查的最后期限。
此外,“现代化的安全框架”这一特性已经被几个 Java EE 开发成员提到,但是此方面工作尚未启动。这可能需要相当大的努力,以及大量其他规范的支持,这是一个整体性问题。顺便说一句,安全框架也是 Antonio Goncalves 关于 Java EE 7 愿望清单中的第 4 个提议,希望 Java EE 8 可以解决这一问题。