一步一步教你用JCA

http://weli.iteye.com/blog/1566189

JCA在J2EE的世界中可能算是比较晦涩的一个领域了,比起大家经常接触到的WebService,ORM,JMS等经常高调出现的J2EE领域的名词,似乎JCA生存在最最阴暗的角落。实际上JCA并不难理解,而且可以说JCA是J2EE领域中最为重要的一部分,是它将J2EE中各组件联系在了一起。本文希望能够用更平实的语言和介绍方面来带大家进入到JCA的世界,真正理解这项重要技术。


本文是上篇,我将在这篇文章中简单介绍JCA的概念。在下篇当中,我在Red Hat北京研发中心的同事lgao会带大家手把手在JBoss AS7中使用JCA开发一个示例项目。

什么是J2EE

从文字角度上说,J2EE的全称叫做Java Platform, Enterprise Edition。即Java企业版。另外,J2EE这个词已经是过去式了,现在叫JavaEE。

从代码角度上说,大多数JDK中包含的javax.*的包都属于J2EE的范围:

Java代码
javax.faces.*
javax.faces.component.*
javax.servlet.*
javax.enterprise.inject.*
javax.enterprise.context.*
javax.ejb.*
javax.validation.*
javax.persistence.*
javax.transaction.*
javax.jms.*
javax.resource.*
...



从理解的角度上来讲,J2EE是Java提供给我们的一个超级庞大的类库及接口规范,它包罗万象:

* WebService
* 数据库
* 消息中间件
* 事务管理
...

可以说,你在开发过程中想到遇到的问题,几乎都能从J2EE中找到相关的规范与实现了这些规范的工具,比如我举些例子:

* WebService下面有基于XML的JAX-WS规范,以及基于REST的JAX-RS规范。实现了这些规范的开源项目有:Apache CXF,RESTEasy等
* 数据库有JPA规范,相关的开源工具当然是大名鼎鼎的Hibernate。
* 消息中间件有JMS规范,实现了这一规范的开源工具包括HornetQ,Apache ActiveMQ等等。

所以说,Java社区最大的特色可能就是各种J2EE规范及数量庞大的实现了这些规范的开源项目了,这是任何其它语言社区所不具备的一个特点。

之所以是这样,有技术和非技术两方面原因。在非技术层面,由于世界上最大的软件公司Oracle,IBM及世界上最牛的开源公司Red Hat在用$$$大力砸进Java,造就了Java的繁荣。技术方面的原因,由于Java本身良好的语言特性,优秀的性能以及稳定的虚拟机技术,使得Java成为天然的构建商业应用的语言。

最终,一切这些既成事实,造就了Java社区今天的样貌。

在J2EE的世界当中,这许许多多的规范和技术里面,可能大家会觉得有难有易,有深有浅。比如在开发项目中经要常用到的Hibernate及其实现的JPA规范,由于用的人多,文档多,再加上天天用,和数据库打交道基本都用它,所以可能会觉得相对比较简单。

至于本文中要介绍的JCA这个J2EE的家庭成员,可能对很多人来讲就觉得很陌生,因为平时可能用到不多,文档少,涉及到的概念比较晦涩,所以感觉上很难。

其实JCA并不难,并且用处很大,虽然可能你不直接用到它,但可能你已经在日常开发过程中使用到了它。假如你用JBoss AS服务器或者是WebShpere服务器来部署你的项目,那么你已经在使用JCA技术了。

因此本文的目的是在概念上让你对JCA有一个熟悉,让它变得不那么陌生。

什么是JCA?

JCA的全称是J2EE Connector Architecture,它定义了一个连接J2EE平台和Enterprise Information Systems(EIS)的标准架构,使得各个EIS能够接入到Application Server当中。

好吧,如果你现在并不了解JCA,那么上面的定义基本上是天书。别着急,下面开始进行详细的讲解:

什么是EIS?

EIS,全称: Enterprise Information System, 是一个虚的概念,用简单明了的话来讲,就是你现有的系统资源。比如你现在在一个企业里面,这个企业原来开发了几个项目,分别是A,B,C。A是一个Web项目,用Servlet开发的;B是一个FTP服务器,上面有些文件;C是一个数据库,里面有点数据。那么,A,B,C都叫EIS。总之就是你现有的杂七杂八的一些IT资源。常见的 EIS 多为: Database, ERP, SAP 等。大家经常用到的 JBoss 下 DataSource 管理就是 JCA 的一个典型应用。

什么是J2EE Application Server?

J2EE Application Server就是支持各种(最好是所有)J2EE技术的应用服务器。比如开源的JBoss AS,或者是WebSphere,这些都是J2EE Application Server。因为它们支持各种J2EE的标准和框架。

比如你做了个和数据库有关的项目,是基于JPA接口规范做的,那么你既可以把它部署在JBoss AS里面,用Hibernate支持跑起来你的项目,也可以部署在WebSphere服务器里面,使用另一套解决方案。

因此,这些实现了J2EE各个规范的服务器,就叫做J2EE Application Server。

那么Tomcat算不算J2EE Application Server呢?

严格来讲,Tomcat不能算是J2EE Application Server,它只能说是一个Servlet容器,虽然Servlet标准也是J2EE世界中的一员。

Tomcat支持的J2EE组件太少了,它不包含对J2EE的事务标准JTA的支持,也不支持JMS,不支持JPA(没有Hibernate这样的组件),不支持EJB,不支持各种WebSerivce。。。

当然,你可以在Tomcat的基础上打造一个准J2EE Application Server。比如,你可以在自己的项目里面加上Hibernate,加上ActiveMQ,加上WebService,加上OpenEJB。。。

但是到最后,你会发现这样做的结果是花了大量的时间在搭建环境上面,并且最后弄出来的东西其实也并不是J2EE Application Server。因为它缺少一些最最核心的东西:

* 分布式事务处理能力
* 群集解决方案
* 接入企业现有IT资源

因此,一般使用Tomcat的项目,都不太会考虑用J2EE技术来进行技术架构,而采用一些更为轻的解决方案,比如Springframwork + Hibernate + Struts等等。然后再通过后期一些别的技术来考虑群集和可扩展的问题。那是另一种技术方向,在初期比较轻快,开发周期短等优势,当然也有它的局限,面向不同规模和不同性质的应用。

什么是JCA?(again)

在理解了上面一大堆概念以后,我们现在要再次回到这个问题上面:

* 什么是JCA?

我们再来重复一开始给出的定义,稍微简化一下:

_JCA就是把你的EIS接进你的Application Server,同时让其它的J2EE组件可以访问到你的EIS。_

什么是接入?

在JCA的定义中,接入这个概念比较模糊,到底什么是接入?对于EIS资源来讲,用户日常的使用不就是接入了吗?比如:我们有一个FTP服务器,用户每天在下载文件;我们还有一个HTTP服务器,上面跑着一些Web服务,用户在用。那么为什么还需要“接入”呢?

是的,对于用户来讲,独立的使用这些IT资源,也是可以的。但是对于一个企业来讲,它可能有很多的历史积累,需要把这些历史积累下来形成的资源整合到一个统一的平台上面去,形成一个完整的项目,提供给用户去使用。

这样的整合,往往并不是简单的已有的东西拼凑在一起,可能要在已有系统的基础上面做改造,然后将它们统一整合起来,形成完整的一个系统。这里面有很多要考虑的东西,既包括代码开发层面,也包括部署层面,因此是一个相当复杂的系统工程,每家企业可能有各自的解决方法。其结果,有成功,也有失败。

在J2EE的世界中,为了解决这一问题,Java标准委员会(JCP, http://jcp.org/en/home/index)制定了JCA标准,专门用于将这些系统资源(EIS)接入到J2EE的Application Server当中。比如一些使用场景:

* 我如何将我已有的FTP服务器接到JBoss AS中?
* 我如何将我的数据库资源接到WebShpere里?
* 我原来自己开发了一个代码框架,我可不可以在JBoss EAP的环境中继续使用我的这些代码并且保证它和其它使用了EJB,WebService,JMS技术的一些JBoss EAP中开发的项目整合在一起?
* 我有一个已有的系统,一个数据库,一个Web服务,我可不可以让它们几个在JBoss AS中运行时,有统一的事务管理?


如果没有JCA标准,可能上面这些问题并不好回答,甚至于根本就没有标准答案。但是有了JCA标准,让EIS的接入,有了统一的规范可以遵守,过去的经验可以利用,资源可以被积累。在JCA标准中,最重要的就是它定义了“接入”的概念。也就是说,JCA标准告诉了你,什么的情况下,一个系统叫做“接入”了应用服务器。

总的来讲,JCA把要接入的叫做Contract(合约)。JCA定义了三个Contract:

* Connection management (连接管理)
* Transaction management (事务管理)
* Security (安全规范)

连接管理

在连接管理当中,J2EE 应用服务器提供连接池的管理。 部署在 J2EE 应用服务器里的RAR(什么是RAR?这里卖个关子,文章最后一节中会讲解)按照规范要求,提供打开连接方法,关闭连接方法等等,让J2EE的应用服务器可以方便的访问EIS。

事务管理

同理,事务管理规范要求待接入的EIS要提供相关的事务功能,这样,当EIS资源参与J2EE的应用服务器的整体业务时,可以参与到整体的事务中来。

事务管理定义了本地事务和分布式事务两方面的接口规范。

安全规范

在安全规范中,定义了EIS要如何参与整体系统的统一认证过程。

小结

通过规范以上三个层面,JCA标准告诉了你该如何将EIS接入J2EE的应用服务器,从而形成一个整体。另外,我们需要注意:

* 并不是所有的EIS在接入时都需要实现上面三个contract,根据自己的需要,接入必须的部分就可以了。比如FTP服务器,我们可能并不需要接入事务管理。
* 不要将EIS误解为只能是以前旧有的系统。实际上在J2EE的应用服务器中,很多组件都是通过JCA的架构规范被集成在一起的。比如JBoss AS中的HornetQ,Hibernate等很多组件都是通过JCA规范与JBoss AS服务器集成在一起的。

接下来,我们来看看这张图:




图片来源 - http://java.sun.com/j2ee/white/images/image9.gif

细心的读者可能注意到在System Contracts和EIS之间有个ResourceAdaper,这是什么呢?接着往下看:

什么是ResourceAdapter?

从图中可以看出ResourceAdapter就是实现上述这些Contracts的实际组件了,我们要使用JCA的话,主要的工作就是实现ResourceAdpater中的各个接口,调用EIS中的资源,将EIS接入到应用服务器当中。因此,代码的工作在这里。

实现好的ResourceAdapter项目,将打包成RAR形成,部署到应用服务器当中,用于和EIS交互。我们知道,常用的Java项目封装方式包括:RAR,WAR,EAR。。。而RAR就是JCA要求的项目封装形式了。


下面再来一张图帮助理解:



图片来源 - http://java.sun.com/developer/technicalArticles/J2EE/connectorclient/resourceadapter_fig2.gif

有关ResourceAdpater的撰写和具体的接口规范等,将在本文的下篇中,由我的同事lgao为大家讲解,本文中不详细展开。

参考资料

Connect the enterprise with the JCA - http://www.javaworld.com/javaworld/jw-11-2001/jw-1121-jca.html

Introduction to the J2EE Connector Architecture - http://www.ibm.com/developerworks/java/tutorials/j-jca/

Use cases for JCA - http://stackoverflow.com/questions/4157776/use-cases-for-jca

Choosing among JCA, JMS, and web services for EAI - http://www.ibm.com/developerworks/webservices/library/ws-jcajms/index.html

Java Platform, Enterprise Edition - http://en.wikipedia.org/wiki/Java_Platform,_Enterprise_Edition

The J2EE Connector Architecture's Resource - http://java.sun.com/developer/technicalArticles/J2EE/connectorclient/resourceadapter.html

http://weli.iteye.com/blog/1591180

在本文中我们要用到的EIS是一个Servlet的服务,运行在一个JBoss AS服务器上(实际上运行在哪里无所谓,是什么也不重要。因为JCA标准中,并没有对EIS的形式或内容做要求。可以是文件,数据库,FTP服务,或像本文要用到的这个HTTP Servlet服务)。

这个项目的功能是列出自己电脑上的目录。我们将这个项目命名为:

* services-1.0.0.war

然后我们要使用另一台JBoss AS服务器做为Application Server,在这上面开发一个ResourceAdapter,用RAR的形式部署,将EIS接进来。将这个项目命名为:

* listfiles-0.1.rar

最后,我们要在Application Server上面开发一个Web应用,使用这个ResourceAdapter为我们接入的EIS资源,提供给最终用户进行使用。这个项目名为:

* listfiles-0.1.war

示例的整体架构图如下:



接下来是实施过程:

制作EIS

在一般的JCA开发过程中,应该是没有这步的,因为我们是要将已有的EIS通过ResourceAdpator接进Application Server。但是因为这个例子要为大家展示完整的过程,因此我们要首先动手制作一个EIS。

首先使用maven[1]创建一个webapp:

Bash代码



我们要做一个Servlet,这个Servlet的功能很简单:用户给出一个dir目录,Servlet列出这个目录中的文件,就相当于ls命令:

Java代码
package org.jboss.jca.sample.eis;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = {"/listfiles"})
public class ListFilesServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String dir = request.getParameter("dir");
        StringBuilder sb = new StringBuilder();
        if (dir != null && !dir.isEmpty()) {
            File file = new File(dir);
            if (file.exists() && file.canRead() && file.isDirectory()) {
                for (File f : file.listFiles()) {
                    if (f.isDirectory()) {
                        sb.append("drwx------\t" + f.getName() + "<br />\n");
                    } else if (f.isFile()) {
                        sb.append("-rwx------\t" + f.getName() + "<br />\n");
                    }
                }
            }
        } else {
            sb.append("Unkown Directory: " + dir);
        }
        request.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.println(sb.toString());
        out.flush();
    }

}



这就是这个EIS的全部功能了,接下来将项目打包:

Bash代码



生成services-1.0.0.war,然后我们将它部署到JBoss AS服务器上,这个项目就算弄完了。

制作ResourceAdapter

接下来我们要制作核心部分ResourceAdapter。在这里,我们要用到JBoss社区的JCA标准实现框架IronJacamar[2]。

IronJacamar下载完成后,切换到:

Bash代码



运行:

Bash代码



按照提示输入:



在上述提示中, 红色下划线标记的为输入,其他因为采用提示给的默认值,因此直接回车就可以。其中:

Bash代码



这个配置指向你的EIS所在机器的IP地址。此外注意到我们设置中的Transaction Support和Re-authenticatiion都是No。也就是说,我们不准备在这个ResourceAdapter中实现事务管理contract和认证contract。是一个相当简单的ResourceAdapter。

完成后,会在当前目录下产生一个叫做out的目录,并生成了一系列的Java代码,下面是out目录结构:



我们看一下相应的类图:



* 在JCA规范中,暴露给用户的连接管理接口是ConnectionFactory。在本例当中我们的ConnectionFactory为ListFilesConnectionFactory。
* 通过ListFilesConnectionFactory.getConnection()获取到ListFilesConnection实例。
* ListFilesConnection 实例通过 ListFilesManagedConnection与相应的EIS 交互。
* ListFilesMangedConnection代表和EIS的物理连接;ListFilesConnection是这个物理连接的Handler。

首先我们实现ListFilesConnection接口,定义一个方法:

Java代码
/** 
* Call the EIS ListFilesServlet and get response
*/
public String listFiles(String dir);




然后在ListFilesConnectionImpl中实现它:

Java代码
...
private ListFilesManagedConnection mc;
...
public String listFiles(String dir)
{   
    return mc.listFiles(dir);
}



注意到ListFilesManagedConnection是实际要实现这个方法的地方,因此,接下来我们要在ListFilesManagedConnection中实现与EIS实际交互的逻辑。因为我们的EIS是一个Servlet的Web服务,因此通过网络调用它,并获取返回值,实现EIS的接入:

Java代码
/**
 * List Files of directory 'dir' in EIS machine.
 *
 * @return a String contains all files in the directory
 */
String listFiles(String dir) {
    ListFilesResourceAdapter ra = (ListFilesResourceAdapter) this.mcf.getResourceAdapter();
    String listFilesServiceURL = ra.getListFilesServiceURL();
    String listFilesServiceParam = ra.getListFilesServiceParam();
    StringBuilder sb = new StringBuilder();
    java.net.HttpURLConnection conn = null;
    try {
        String dirEncoded = java.net.URLEncoder.encode(dir, "UTF-8");
        String url = listFilesServiceURL + "?" + listFilesServiceParam + "=" + dirEncoded;
        conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
        conn.setDoOutput(true);
        conn.connect();

        java.io.InputStream in = conn.getInputStream();
        java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(in, "UTF-8"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }
    return sb.toString();
}




Java代码挺简单的,接下来我们要编辑IronJacamar的配置文件:

Xml代码



下面是配置的详细内容,很容易理解:

Xml代码



ResourceAdapter的全部代码工作至此完成了,接下来将项目打包:

Bash代码  



生成listfiles-0.1.rar,这个就是我们需要的RAR文件了。将这个文件部署到Application Server当中。

创建客户端

有了EIS,也有了ResourceAdapter来接入这个EIS,接下来我们要写一个客户端应用,来通过ResourceAdapter使用这个EIS。请注意这里面说的客户端并不是最终用户,而是通过ResouceAdapter来使用EIS的应用,我们称其为客户端。

还是使用mvn来创建一个Web项目:

Bash代码



仅需要撰写一个jsp文件,打开:

Xml代码



内容如下:

Java代码
<%@ page import="org.jboss.jca.sample.listfiles.*" %>
<html>
<body>
<h2>Hello JCA!</h2>
<form action="index.jsp">
Directory: <input type="text" name="dir" />&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" value="List Files"/>
</form>
<br />
<%
         String dir = request.getParameter("dir");
         String files = "";
         if (dir != null && dir.length() != 0){
             String jndiName = "java:/eis/ListFilesConnectionFactory";
             javax.naming.InitialContext ctx = null;
             try
             {
                ctx = new javax.naming.InitialContext();
                Object obj = ctx.lookup(jndiName);
                if(obj != null){
                    ListFilesConnectionFactory connFactory = (ListFilesConnectionFactory)obj;
                    ListFilesConnection conn = connFactory.getConnection();
                    files = conn.listFiles(dir);
                    conn.close();
                }
             }
             catch (Exception e)
             {
                e.printStackTrace();
             }
             finally
             {
                try
                {
                   ctx.close();
                }
                catch (Exception e)
                {
                   e.printStackTrace();
                }
             }

%>
<div>Files under directory <%= dir %> : <br /> <%= files %></div>
<%
         }
%>
</body>
</html>



功能很简单:给用户一个输入表单->输入需要显示的目录->将用户的请求提交给ResourceAdapter->ResourceAdapter去调用EIS并返回结果。

虽然功能不难,但是代码当中包含了很多ResourceAdapter的调用方法:

Java代码
String jndiName = "java:/eis/ListFilesConnectionFactory";

javax.naming.InitialContext ctx = null;
ctx = new javax.naming.InitialContext();

Object obj = ctx.lookup(jndiName);

ListFilesConnectionFactory connFactory = (ListFilesConnectionFactory)obj;
ListFilesConnection conn = connFactory.getConnection();

files = conn.listFiles(dir);

conn.close();



接下来我们需要编辑一下:

Bash代码  



这个文件,因为在JBoss AS 7中, 要求这个文件中包含项目所依赖的ResourceAdapter信息,格式如下:

Xml代码



因此我们在这个文件中添加内容如下:

Xml代码



指定这个客户端项目依赖于listfiles-0.1.rar。最后还是项目打包:

Bash代码



生成listfileweb-1.0.0.war。

部署

至此为止,我们应该有了三样东西:

* services.war - EIS
* listfileweb-1.0.0.rar - RAR
* listfileweb-1.0.0.war - Client

我们要部署这些组件:

将listfileweb-1.0.0.rar和listfileweb-1.0.0.war部署在机器A的JBoss AS上面

假设 JBoss AS 7 的目录在 ~/softwares/jboss-as/jboss-as-7.1.1.Final/, 那么我们运行命令:

Bash代码



运行完以上指令, JBoss AS 7 就会启动, 之后我们来部署 listfiles RAR 和 listfileweb WAR,打开另外一个控制台,然后输入:

Bash代码



如果两条指令没有错误提示, 部署就成功了。 我们可以确认下:

Bash代码



将services.war部署在机器B的JBoss AS上面

部署services.war的方法没什么不同,不再赘述。但是这台机器上面的JBoss AS7的配置要稍做改变,因为我们需要让机器A中的ResourceAdapter能访问到这台机器上面的EIS资源,而AS7默认只侦听localhost,所以要做出配置修改。打开:

Bash代码  



修改:

Xml代码



为:

Xml代码



然后启动AS7服务器:

Bash代码



测试

万事俱备,接下来进行测试。在机器A上面访问Client:

Html代码
http://127.0.0.1:8080/listfileweb-1.0.0/



效果如下:



在输入框里写上要查看的目录文件列表,此时RAR会调用EIS,返回EIS所在的机器B中的目录内容:



以上,我们就完成了这个例子全部内容的展示。

小结

本文通过一个例子向大家展示JCA中ResourceAdapter的开发过程,以及对它的使用方式。虽然这个例子非常简单,仅实现了JCA标准中提供的三个contracts中的最基本的Connection Management,但是它的流程是完整的,在此基础上,你可以继续深入阅读JCA的相关资料,进一步学习它,也可以为阅读现有EIS的ResouceAdapter的源代码打下良好基础。相信这会是一个好的起点。

代码

本文中用到的三个代码我放在了github上面,有兴趣可以迁出:

EIS

Xml代码



RAR

Xml代码



Client

Xml代码



文中用到的工具

Maven

Maven 是项目管理的工具, 可以很方便的进行项目的编译,打包,测试。可以从以下网址找到下载连接。

Xml代码



笔者使用的 maven 版本是:

Bash代码



IronJacamar

IronJacamar 是 JBoss 的 JCA 1.6 实现,它提供了生成 JCA 代码的工具和 standalone 的环境用来测试,从以下地址下载 IronJacamar:

Xml代码



本文使用的IronJacamar版本为1.0.10.Final。

JBoss AS 7

我们在这个例子中使用JBoss AS 7做为应用服务器还有EIS的例子工具。下面是网址:

Xml代码



笔者使用的 JBoss AS 7 版本是: 7.1.1.Final。

参考资料

JSR 322: JavaTM EE Connector Architecture 1.6 - http://jcp.org/en/jsr/detail?id=322

IronJacamar 1.0 User's Guide - http://docs.jboss.org/ironjacamar/userguide/1.0/en-US/html_single/

IronJacamar 1.0 Developer's Guide - http://docs.jboss.org/ironjacamar/developerguide/1.0/en-US/html_single/

展开阅读全文

没有更多推荐了,返回首页