J2EE信息系统集成解决方案

 在当前Java开发中,Web占据很大空间, 10个Java程序员就至少有6个是搞Web方面开发的,但不管是C/S还是B/S, 软件最终的目的只有一个,那就是对各种服务的集成.  在软件技术发展到今天,EIS的集成出现了2大主流,即SUN的J2EE(JavaEE)方案和MS的.NET方案,他们要作的都是将不同的服务进行集成后统一接口暴露给客户端,比如在J2EE里,实现对分布环境下服务的集成---RMI等,传统的CORBA等,以及.NET的remoting等,当然我们这里只讨论Java的集成方案.
  在J2EE集成中,集成大体分为2中,第一是Java系统之间的集成,另外一个是Java与其他语言开发的信息系统之间的集成.下面分开讨论.
  第一: Java系统之间的集成: 该情况下集成比较简单,只要双方提供服务接口即可,比如服务方提供RMI远程接口或者直接以EJB的形式把接口暴露给客户端,在这中情况下,最核心的部分就是RMI,应为EJB也是架设在RMI基础之上的一个规范,下面简要介绍RMI的数据流原理以及给出一个开发实例:
    RMI开发分为2个部分,一个是服务器端开发,一个是客户端开发,服务器端提供远程业务接口以及服务实现,而客户端需要提供和其想匹配的远程业务接口和Stub存根,在此需要特别说明的是,客户端的远程接口和服务器端的远程接口一定要具有相通的SerialUID,否则他们是无法通信的,在这里我详悉说明下Java对象在网络上传输的原理:
    如果一个对象需要在网络上传输,它一定是一个可序列化的,这个我想几乎所有Java程序员都知道,实现java.io.Serializable接口即可,但通信双方,一边将该对象发出去,另外一边就必需用该类进行接收,我们要作的就是分别把这个dto打2个jar包,一个放到服务器端,一个放到客户端 ,这样它们就能通信, 这里我们作一个实验,你第一次编译的时候(javac),把生成的class打到jar包里,然后再javac一次,把class打包到另外一个 jar包里,分别把这2个jar包放到客户端和服务器端, 运行程序,你会发现会出现序列号不一致的文体, 读者肯定会问这是为什么? 原因就是这2个类不一样,应为根据java规范,可许列化的类,必需提供一个private static final long serialUID 这个Field, 我们可以在程序里 显式 设置,如果不显式 设置, javac在编译源代码的时候会自动生成一个放到class文件里 (不信你javap下看看),正是由于2次javac产生的随机serialUID不一致,所以才造成了刚刚上面的哪个错误出现,现在解决的办法有2个,第一是 只javac一次,把同一个 class打2 次包, 分别给客户端和服务端,第2是显式指明serialUID在代码里,这样即时javac N次也不要紧. }
  现在继续讲RMI , 当用户调用客户端远程接口的时候,比如:Naming.lookup("rmi://192.168.0,1//serviceName")的时候,JVM会察觉到这是一个RMI请求,这时它会把这个路由信息(192.168.0.1/serviceName)通知给Stub,而Stub就负责向远程服务器的RMI 中央注册机发送请求,中央注册机调用服务通过这个服务名子(serviceName)来找到注册进来的对象实例,这时候调用这个实例来处理,完了返回值按原路逆向返回,接收端进行反序列话, (注: 序列化和反序列化的任务都是由 2 端的Stub和框架完成的).这样一个远程调用过程就完成了,下面代码说明:
  A. 创建一个远程接口:  Mclaren.java
     package org.mclaren.remote;
     import java.rmi.Remote;
     import java.rmi.RemoteException;
     public interface Mclaren extends Remote {
         public String sayHello(String name) throws RemoteException;
     }

  B. 创建一个服务实现:  MclarenService.java
     package org.mclaren.remote;
     import java.rmi.server.UnicastRemoteObject;
     import java.rmi.RemoteException;
     import java.rmi.Naming;
     public class MclarenService extends UnicastRemoteObject implements Mclaren {
         public MclarenService() throws RemoteException {
              super();
         }
         public void registerService(String serviceName) {
              try {
                  //绑定名称后注册到中央注册机
                  Naming.rebind(name,this);  
                  System.out.println("服务已经起动");
              } catch(Exception e) {
                  e.printStackTrace();
              }
         }
         public String sayHello(String name) throws RemoteException {
               return "Hello :"+name+"  this is processed by RMI service":
         }
     }

    C. 编写服务起起动类:  StartUp.java
     package org.mclaren.remote;
     import java.rmi.RMISecuriryManager;
     public class StartUp {
         public static void main(String[] args) {
             try {
                  System.setSecurityManager(new RMISecurityManager());
                  MclarenService mclaren = new MclarenService();
                  mclaren.registerService("//MclarenService");
             } catch(Exception e) {
                 e.printStackTrace();
             }
         }
     }

    D. 编写安全策略文件 mclaren.policy
      grant {
         Permission java.security.AllPermission ("192.168.0.2,192.168.0.3","");
      };
      注解: 这段话的意思是 允许  192.168.0.2,192.168.0.3这2个机器的任意端口使用本服务作任何事情,当然你可以改 .

    E. 为服务作准备:  打开cmd 或者 终端(Linux),到JDK_HOME/bin 下执行 rmiregistry明令起动RMI中央注册机 ( rmiregistry的语法是: rmiregistry <端口>  ,默认为1099).
    到刚哪个工程的classes下,执行明令: rmic org.mclaren.remote.MclarenService 来生成客户端 Stub,然后把stub和远程接口一起打包成client.jar文件:
    F. 起动服务: 假设: 我们工程的类输出目录在: F:/RMITest/classes下,而mclaren.policy 在F:/RMITest下 .那么在cmd里执行:
    java -classpath F:/RMITest/classes org.mclaren.remote.StartUp -Djava.rmi.server.codebase=file:///F://RMITest//classes/ -Djava.security.policy=file:///F://RMITest//mclaren.policy
完了后会发现输出: 服务已经起动

现在开发客户端: 把client.jar导进来
    public class Client {
        public static void main(String[] args) {
            try {
                  Mclaren mclaren = (Mclaren) Naming.lookup("rmi://192.168.0.1:1099//MclarenService");
                  mclaren.sayhello("mclaren");
               } catch(Exception e) {
                   e.printStackTrace();
               }
         }
     }

执行后会 出现 : Hello : mclaren this is processed by RMI service"
对于EJB就没这么复杂了,大家自给看书,下面将Java如何与C/C++进行集成.
  A. Java调用C++:  Java 调用C++,就得用JNI接口,关于JNI的概念我就不多废话了,自己去so,(在国内别的不好着,找概念的东西还是一找一堆). 下面举例子:
    (1) 首先创建一个Java文件: Mclaren.java
        package org.mclaren.jni;
        public class Mclaren {
            static {
                System.loadLibrary("Mclaren');  // load Dll or so
            }
            public native void sayHello(String name);
         }
     (2) 生成头文件: 在classes目录下输入: javah org.mclaren.jni.Mclaren 会生成一个C的头文件 org_mclaren_jni_Mclaren.h
     (3) 新建一个VC工程,把 %JAVA_HOME%/include 和 %JAVA_HOME%/include/win32添加到include里,或者直接把jni.h 和jni_md.h  copy过来也可以 ,然后新建一个cpp文件 Mclaren.cpp(我采用C++写 ) ,这样你VC工程目录下将含有4个文件:  jni.h, jni_md.h. org_mclaren_jni_Mclaren.h, Mclaren.cpp
    其中Mclaren.cpp内容为:
     #include <iostream>
     #include "org_mclaren_jni_Mclaren.h"
     using namespace std;
     JNIEXPORT JNICALL org_mclaren_jni_Mclaren_SayHello(
           JNIEnv * env, jobject obj, jstring name) {
           char *str = (char *) name;
           cout<<"C++输出 :"<<str<<endl;
           delete str;
     }

将上面的工程打包成一个dll后放到硬盘上任意地方,假设D://lib//Mclaren.dll, 我们只要把这个dll放到程序的运行时 librarypath 里就可以 .
下面编写测试类:
    public class Test {
        public static void main(String[] args) {
             Mclaren mclaren = new Mclaren();
             mclaren.sayHello("Mclaren");
         }
    }

假设这个工程的 classes目录是: F://JNIJ2C/classes
那么:  java -classpath F://JNIJ2C/classes Test -Djava.library.path=D://lib//Mclaren.dll

这时会输出:  C++输出 Mclaren.

   
   B. C++ 调用Java:  C++调用Java的时候,就需要用C++来起动Java虚拟机,来装载类,下面我分别在Windows环境下和Linux环境下讲述:
    (1) Windows环境下:
        a. 新建一个C++工程(不需要支持MFC), 把JAVA_HOME/include/jni.h JAVA_HOME/include/win32下的 jni_md.h copy 到C++工程目录下,然后把 JAVA_HOME/jre/bin/client/jvm.dll 写进系统PATH ,再把JAVA_HOME/lib/jvm.h 添加到VC的工程lib里.
        b. 新建Mclaren.cpp ,内容如下:
         #include "jni.h"
         #include <iostream>
         using namespace std;
         int main() {
            JNIEnv *env;
            JavaVM *jvm;
            JavaVMOption options[3];
            JavaVMInitArgs args;
            memset(&args,0,sizeof(&args),)
            args.version = JNI_VERION_1_4;
            args.nOptions = 3;
            args.option = options;
            args.ignoreUnrecognized = JNI_TRUE;
            options[0] = "-Djava.class.path=.";
            options[1] = "-Djava.library.path=.";
            options[2] = "-verbose:jni";
            
            int ret = JNI_CreateJavaVM(&jvm,(void **)&env,&args);
            if(ret < 0) {
                cout<<"起动JVM 失败"<<endl;
                return -1;
            }
            //我们加载上面的RMI Client类
            jclass cla = env->FindClass("org/mclaren/remote/Client");
            //取得 main方法, 第3个参数是Java签名
            jmethodID init = env->GetStaticMethodID(cla,"main","([-Ljava.lang.String)V");
            env->CallStaticMethod(cla,init,NULL);
            jvm->DestroyJavaVM();
            return 0;           
         }

     VC编译后,执行.  取得的效果和用java.exe起动是一样
  
    (2) Linux环境下 :
        a. 代码不变,因为上面用的是标准C++ 库
        b. 设置好环境变量JAVA_HOME, CLASSPATH和 PATH
        c. 在 .bash_profile里追加一条:
             export LD_LOBRARY_PATH=$JAVA_HOME/jre/lib/i386/client
        到Mclaren.cpp所在的目录下输入命令 :
      g++ -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -L $LD_LIBRARY_PATH -o Mclaren Mclaren.cpp -ljvm
     注意" -ljvm是小写的L
      这样就会产生一个Mclaren的可执行文件,执行一下,效果同上.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值