JCA——一个名不见经传却重要的 JavaEE 规范

阅读数:6783 2014 年 3 月 20 日

话题:Java语言 & 开发架构

JCA(Java EE Connector Architecture)规范可以说是 JavaEE 规范集合里最“默默无闻”的,在 JavaEE1.3 规范发布时就加入了,比现在重要成员 JPA, CDI 等都早了很多。从应用开发角度来看,开发一个很普通的 Web 应用程序,只有几个页面,使用 Servlet 就可以完成,用 JDBC API 保存信息到数据库中,部署这个应用到 JavaEE 应用服务器中时,就会用到 JCA 技术。这个很简单的应用程序只用了庞大的 JavaEE 规范集 30 多项中的 Servlet 和 JCA 两项规范而已。那么,如此重要的规范,为何很少人知晓呢,本文就解释一些其中的原委。

JCA 原意是 Java 企业版本连接器体系结构,这样一个生涩的词语不能很好的描述它的功能。简单来说,这个规范的作用就是定义如何连接 JavaEE 应用服务器和外部的信息系统,这类系统包括但不局限于数据库,消息中间件,分布式缓存系统,ERP/CRM 为代表的企业软件系统,Tuxedo 等事务 / 消息中间件等。我们知道 JavaEE 中的 Enterprise 是企业的含义,这套规范集的设计目标一开始就定义了是为企业应用软件而设计的。在一个企业领域的范畴内,可以运行着很多应用软件,如果一套软件是用 JavaEE 规范技术开发并部署运行在应用服务器中,并且它需要和其他应用系统进行信息交互, JCA 就可以发挥强大的功能。

JCA 产生于 J2EE 最为繁荣辉煌的 1.3 版本时代,JCA 1.0 版本由 JSR16 提出,当时 J2EE 整个技术栈已经比较完备,一个需求产生了:如何把 JDBC/JMS 等连接管理统一起来?与此同时,BEA 公司的 Tuxedo 产品也面临和 J2EE 进行集成的问题。JCA1.0 版本定义了连接管理,以及在连接之上如何管理事务和安全,但只考虑了 Outbound(出站) 单向请求的需求。

接下来 J2EE 出现了群雄混战的局面,更多的产商对 JCA 规范产生了兴趣,包括众多的 EAI 集成软件厂商和 ERP 巨头如 SAP 等等,JCA1.5 规范在 2003 年完成,这个版本就很完备了,加入了 Inbound(入站) 消息流向,定义了 WorkManager 等重要内容。直到今日,很多 Resource Adapter 也只支持 1.5 规范。

在版本 5 时 J2EE 重新命名为 JavaEE,这个大版本主要聚焦在 JPA 和 EJB3,JCA 没有变动。JavaEE6 版本发布时 JCA 升级到 1.6,JSR 编号是 322,除了功能完善以外,主要是加入对 Annotation 的支持,从此可以选用 XML 或者 Annotation 描述 JCA 的相关实现类。

去年发布了 JavaEE7,JCA 作了微小的修改,升级到 1.7,但还是沿用 JSR322 规范编号。所以我们现在看到的最新支持 JavaEE7 的应用服务器中的 JCA 规范是 1.7 版本。在最新的 Wildfly(原 JBossAS)应用服务器中,数据库连接池,JMS 连接,接受消息 MDB 信息等配置信息,都是 IronJacamar(JBoss 开源组织 JCA 实现) 可以识别并处理的配置选项。

让我们看一下标准的 JCA 体系结构图。

四个部分是应用服务器 (Application Server),应用组件 (Application Component), 资源适配器 (Resource Adapter) 和企业信息系统 (Enterprise Information System)。

我们一般开发的应用是将 War 部署在 WebServer 中,分别对应于应用组件和应用服务器。企业信息系统是可以独立运行的应用系统,比如数据库,ERP 等,资源适配器是为了和企业信息系统进行连接而设计的连接适配器软件,可以把 JavaEE 应用服务器和外部应用系统连接起来,并提供资源服务给应用组件来使用。

这里大家可能会产生疑问,一般应用可以通过 JDBC 或者 JMS 接口获得连接,为什么还要定义 JCA 规范接口呢。答案简单说就是为了统一接入层的 API 和被容器管理。应用服务器中的资源池容器(可以称为 JCA 容器)需要管理所有的外部信息系统连接,统一调度给应用程序使用。对于应用开发人员来说,使用这些资源就很简单,只需要通过 JNDI 就可以获取到可用资源,得到引用并进行调用,使用完毕后关闭,容器会进行回收,放回可用资源池中供后续使用。所有这样的资源都会被资源容器识别并管理,JCA 的规范就定义了这样的接口。我们看到在 JCA Javadoc 中定义的很清楚,spi 包里面的就是让资源适配器实现的接口集合。

让我们稍微深入代码看重要接口:

入口点是 ResourceAdapter,这个接口代表了资源管理器的实例,方法定义了实例的生命期回调方法,其中 start 方法的参数实现了 BootstrapContext 接口,可以把应用服务器的服务能力作为上下文传入。

通过配置信息,可以获得 Outbound 信息入口接口 ManagedConnectionFactory,通过这个接口的方法,可以获得被管理的连接 ManagedConnection。我们要理解在 JavaEE 的世界里,几乎任何资源都是被管理的,或者可以看成是逻辑意义上的资源。通过 JNDI 获取到的接口实现类,在不同应用场景中,后台程序已经做了很多工作:有可能加入了丰富功能,也有可能是只是一个空的代理引用,等需要时再去访问真正的对象,达到节约占用资源的目的。通过 ManagedConnection 接口,应用可以进一步获得实现业务接口的对象,从而和外部信息系统进行交互。

对于 Inbound 来说,开发人员通过描述文件或者 Activation 注解定义,编写 MDB 来接受外部系统传入的消息。这里就引出一个很有趣的话题,我们学习 JavaEE 技术,特别是用到 EJB 时,规范有一个要求是不能创建线程,因为这样会让线程资源很难被容器全面管理。但一个常见的需求就是打开一个端口来接收外部的消息或者调用请求。一般实现方式会创建线程来完成端口侦听和接收消息,这样就违反了 JavaEE 规范要求。那么面对这样的需求该怎么做?这时 WorkManager 就发挥了它的作用。

WorkManager 调度 Work,而 Work 扩展了 Runnable 接口,这样可以把需要执行独立线程的代码逻辑封装到 Work 的实现类中,提交给 WorkManager 去调度执行。一般来说应用服务器会维护线程池来合理分配可用的线程资源,进行高效调度管理。这样类似于打开一个端口去接收消息的需求就可以被满足,绝大多数 JMS 实现的资源适配器就是这样做的。

说了这么多,可能大家觉得也不过如此,以上的需求不用 JCA 似乎也能实现,为什么要搞得很复杂来使用 JCA 呢?这样就引出 JavaEE 核心思想 -- 事务性。

给企业开发应用,事务是一个极其重要的商业因素。我们知道财务会计核心准则之一就是有借必有贷,借贷必相等,这句话就充分体现了事务思想。企业的业务,流程,事件处理,都是有一定的管理规定的,每个涉及商业逻辑的业务系统,都会充分考虑满足业务事务一致性的需求。除了刚才说的财务系统以外,其他的企业软件系统也需要对事务有良好的支持,比如请假被批准了,同时可用年假记录数额也需要减少。整个系统内完成这个业务事务之后,还是处于一个“平衡”的状态,可以说企业应用的绝大多数软件都需要事务支持。

基于 JavaEE 开发的应用,一般来说也需要支持事务,同时和外部系统配合来支持完成一项事务过程。我们知道数据库,JMS 服务器等都是支持事务的,和它们的连接中会带有事务上下文信息,这样就可以通过一定的契约(接口),来进行事务信息的传递。在 JavaEE 的设计思路中,可以通过声明式编程和对象功能加强来屏蔽一定程度的事务处理复杂性,这部分知识在讲述 EJB 核心思想的书籍里都有论述。简单来说是对象通过容器内部传递上下文 (Context) 信息来屏蔽一部分业务开发人员处理事务细节的繁杂编程工作。

这个上下文同时还可以传递安全相关信息,也就是 JavaEE 的安全相关的内容。JCA 同样对连接管理的安全性进行了规范定义,从而可以方便的对应用服务器和外部系统的安全身份,授权信息进行管理和映射。在 JCA1.6 以后,对 Inbound 的事务和安全的定义也完善了。

既然这么好,那我们把 JCA 完全用在 Java 业务软件中如何?等等,JCA 也有一些在技术选型上需要考量的地方。

首先是事务支持,我们知道事务可以说和系统可扩展性是冤家对头。事务过程中必然带有状态,而远程调用服务 / 可扩展的设计原则之一就是无状态的,这个矛盾无法避免。那么在不需要事务支持或者要求不高的业务范畴,比如论坛,博客等,我们可以选择取消事务支持来提高系统效率。其实这一点也是 JavaEE 技术在互联网领域面临尴尬的原因之一。

其次,JCA 的关注点主要在连接管理上,规范并没有定义拿到连接后如何获取业务对象引用,以及业务对象接口的宽泛程度等内容。所以对于复杂的业务系统来说,资源适配器中绝大多数配置项都是私有的,无法全部规范化, 引入 JCA 对实际应用帮助有限。

第三,连接池是高性能业务系统的核心组件之一,数据库连接池的管理是运维工作的主要内容。但连接池功能众多,配置繁杂,每个应用服务器实现都不一致,而这部分内容并没有在规范中定义。所以应用在不同服务器间迁移变得很困难,光连接池配置就需要做很多工作。

那么什么场景适合使用呢?如果使用兼容 JavaEE 的应用服务器来开发,比如 JBossAS(WildFly,Redhat JBoss EAP),Weblogic,Glassfish,Webshpere 等,那么已经用上 JCA。此外对需要支持分布式事务的软件系统,进行二次开发,JCA 都是良好的技术选择。典型例子有各种 MQ/JMS 具备事务能力的系统,和 Tuxedo 连接的 WTC 资源适配器等。

还有一个更重要因素,就是 JCA 规范是系统间集成技术经验的一种体现,任何开发者基于 JavaEE 开发,需要和外部系统交互,在设计 / 编码 / 上线运营 / 系统成熟后会发现和目前 JCA 定义的体系架构会非常相似。学习 JCA 规范就能够快速掌握这套架构模型,这就是知识凝聚的力量。

参考链接

[1]: http://www.oracle.com/technetwork/java/javaee/index-138715.html

[2]: https://www.jcp.org/en/jsr/detail?id=322

作者介绍

张建锋,红帽软件高级软件工程师,10 多年中间件产品开发经验,2008 年加入红帽软件参与开发 JBossAS 产品至今,经历了 JBossAS 的三代内核架构变化,完整了解应用服务器产品的技术体系。张建锋在 QCon 北京 2014 大会上将带来技术训练营课程《JavaEE,企业应用互联网化的架构选择探讨


感谢张龙对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。