您的位置:首页 > 编程语言 > Java开发

java框架简介4----Spring+Hessian 远程过程调用

2010-08-06 20:51 435 查看
Spring+Hessian简介:
Hessian能够完成RMI就是远程过程调用,实际上Hessian自己就可以完成这个功能,但是我的目的是将与Spring相关的框架与Spring结合起来,一起完成任务,所有不单独拿出一个章节来讲Hessian。不够,使用方式都是相通的。
 
这次需要完成的任务是这样的,假设在远程有一个作业需要执行,我们写一个客户端,并将这个客户端安装到远程主机上,然后再本机上远程调用客户端的服务,让客户端执行远程主机的作业任务。
 
从上面的分析可知,我们需要完成两个服务,一个是远程执行主机的服务,一个是本地的调用服务。整个程序的结构如下:
远程执行主机服务:



需要用到的jar包:



 
本地执行主机目录:



 
需要的jar包:
 


 
第一步:编写远程主机服务:
要在远程主机上执行作业必然需要对需要执行的作业进行描述,这里对作业的描述如下:
package com.guan.springHessianClientTest.logicModel;
 
import java.io.File;
import java.io.Serializable;
 
public class Job implements Serializable{
    /**
     * 注意作业必须要实现Serializable接口,很明显,作业作为参数在两个主机间传递,必然要进行串行化。Hessian是以二进制的形式进行传输的。
     */
    private static final long serialVersionUID = 1L;
    private String executable;//可执行文件的名字
    private File directory;//执行目录
    private String stdOutFile;//标准输出文档
    private String stdErrFile;//标准错误输出文档
    private String[] args;//程序执行参数
   
 
    public File getDirectory() {
       return directory;
    }
 
    public void setDirectory(File directory) {
       this.directory = directory;
    }
 
    public String getExecutable() {
       return executable;
    }
 
    public void setExecutable(String executable) {
       this.executable = executable;
    }
 
    public String[] getArgs() {
       return args;
    }
 
    public void setArgs(String[] args) {
       this.args = args;
    }
 
    public String getStdOutFile() {
       return stdOutFile;
    }
 
    public void setStdOutFile(String stdOutFile) {
       this.stdOutFile = stdOutFile;
    }
 
    public String getStdErrFile() {
       return stdErrFile;
    }
 
    public void setStdErrFile(String stdErrFile) {
       this.stdErrFile = stdErrFile;
    }
}
上面这个类是个实体类,不多说,大家都明白。
然后实现一个ServiceDao就是服务接口,对应Hessian来说,这个接口是必须的,因为Hessian建立的远程调用,在远程不能过直接对服务的实现调用,而是对服务的接口进行调用,后面还会分析其原因。
package com.guan.springHessianClientTest.ServiceDao;
 
import java.io.IOException;
 
import com.guan.springHessianClientTest.logicModel.Job;
 
public interface ExecuteServiceDao {
    public void submintJob(Job job) throws IOException;
}
 
这个接口很简单,就是提交作业到远程执行。
 
下面给出上面接口的实现:
package com.guan.springHessianClientTest.ServiceImpl;
 
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
 
import com.guan.springHessianClientTest.ServiceDao.ExecuteServiceDao;
import com.guan.springHessianClientTest.logicModel.Job;
 
public class ExecuteServiceDaoImpl implements ExecuteServiceDao{
 
    public void submintJob(Job job) throws IOException {
       Runtime runtime = Runtime.getRuntime();//执行时环境
       Process process = runtime.exec(job.getExecutable(),job.getArgs(),job.getDirectory());
       //开启一个进程来执行提交过来的程序
       BufferedInputStream in = new BufferedInputStream(process.getInputStream());//获得可执行程序的标准输出
       BufferedReader br = new BufferedReader(new InputStreamReader(in));//创建一个reader读取标准输出
      
       BufferedInputStream err = new BufferedInputStream(process.getErrorStream());/*获得可执行程序标准错误输出*/
       BufferedReader berr = new BufferedReader(new InputStreamReader(err));
      
       PrintStream myout = new PrintStream(new FileOutputStream(new File(job.getStdOutFile()))); /*打开标准输出文件*/
       PrintStream myerr = new PrintStream(new FileOutputStream(new File(job.getStdErrFile())));/*打开标准错误输出文件*/
 
       String s;
       while ((s = br.readLine()) != null)
           myout.println(s);/*读取,然后输出到文件*/
       while ((s = berr.readLine()) != null)
           myerr.println(s);
    }
   
}
 
在执行程序的过程中,服务先开启一个进程来执行这个程序,然后将执行的结果输出到文件中。
 
接下来,需要配置远程调用的接口,首先要在web.xml中配置Spring的过滤器,这个可以参考我前面的Spring+Hibernate那篇文章。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">   <servlet>
           <servlet-name>remoting</servlet-name>
           <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
           <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
           <servlet-name>remoting</servlet-name>
           <url-pattern>/remoting/*</url-pattern>
    </servlet-mapping>
</web-app>
 
通过这个配置,很容易看到,凡是以/remoting开始的请求,都会被传递给Spring来处理。
下面要配置Spring:
Remoting-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
      
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd            http://www.springframework.org/schema/aop            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd            http://www.springframework.org/schema/tx            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd            http://www.springframework.org/schema/context            http://www.springframework.org/schema/context/spring-context-2.5.xsd">              <bean id="excuteServiceDaoImpl" class="com.guan.springHessianClientTest.ServiceImpl.ExecuteServiceDaoImpl"/>
        <bean name="/executeManagerService" class="org.springframework.remoting.caucho.HessianServiceExporter">
               <property name="service" ref="excuteServiceDaoImpl"/>
               <property name="serviceInterface" value="com.guan.springHessianClientTest.ServiceDao.ExecuteServiceDao"/>
       </bean>
</beans>
首先创建了一个ExecuteServiceDaoImpl的实现,然后创建了一个远程调用的服务,这个服务中注入了ExecuteServiceDaoImpl的实现。并且说明了接口是ExecuteServiceDao。在远程需要获得这个远程调用的服务(/executeManagerService,注意呀,这个名字前有个/),然后使用接口来完成服务的访问。
 
第二部分 服务端本地调用的编写:
本地调用只写了个测试程序,需要直接从执行服务端拷贝model和dao。然后需要写一个Spring的配置文件,bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
      
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd            http://www.springframework.org/schema/aop            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd            http://www.springframework.org/schema/tx            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd            http://www.springframework.org/schema/context            http://www.springframework.org/schema/context/spring-context-2.5.xsd">                     
       <bean id="myServiceClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
       <property name="serviceUrl">
          <value>http://localhost:8080/SpringHessianClientTest/remoting/executeManagerService</value>
       </property>
       <property name="serviceInterface">
           <value>com.guan.springHessianClientTest.ServiceDao.ExecuteServiceDao</value>
       </property>
       </bean>
</beans>
先创建一个Service的bean,并指明这个Service的url是刚才我们配置那个服务的url,注意我是本机测试,所以使用localHost,并且我的tomcat配置的是8080端口,如果执行服务放在远程主机上,那么要将localHost更换成其ip地址。然后指明要使用的接口是什么。
 
注意在提交端,并没有拷贝服务的实现,只是拷贝了服务的接口。
最后的测试部分代码如下:
package com.guan.springHessianClientTest.RomoteService;
 
import java.io.File;
import java.io.IOException;
 
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import com.guan.springHessianClientTest.ServiceDao.ExecuteServiceDao;
import com.guan.springHessianClientTest.logicModel.Job;
 
public class RMIServiceTest {
    @Test
    public void remoteTest() throws IOException
    {
        ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");//分析Spring配置文档
        ExecuteServiceDao studentService = (ExecuteServiceDao) appContext.getBean("myServiceClient");//获取配置的bean
        Job job = new Job();//新创建一个job,并进行配置
        job.setExecutable("F://programs//vs6.0//redirectionTest//Debug//redirectionTest.exe");
        job.setDirectory(new File("F://programs//NFSWorkSpace"));
        job.setStdErrFile("F://test.err");
        job.setStdOutFile("F://test.out");
        studentService.submintJob(job);//直接调用完成执行
    }
}
 
从上面的例子我们可以看出,整个执行过程就像在本机执行一样,是不是很方便呀!!
测试的程序redirectionTest是用c++写的,代码如下:
#include <iostream>
 
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
 
void main()
{
         cout<<"hello world!!"<<endl;
         cout<<"您好!!!"<<endl;
         cout<<"good good "<<endl;
         cerr<<"err message"<<endl;
         cout<<"after err message"<<endl;
         cerr<<"second errmessage"<<endl;
}
 
最后结果是:在F盘生成两个文件
Test.err
err message
second errmessage
 

Test.out
hello world!!
您好!!!
good good
after err message
 
实际上这已经是个小的网格的概念,作业调度系统在远程调度作业到执行主机去执行作业。
 
远程过程调用就像您在本地调用方法一样轻松的完成您的任务,这是一个好方法。
 
如果您在提交端不想使用Spring,可以用下面的方法,似乎更简练些:
      
        String url = " http://localhost:8080/SpringHessianClientTest/remoting/executeManagerService ";
        HessianProxyFactory factory = new HessianProxyFactory();
        ExecuteServiceDao executeServiceDao= (ExecuteServiceDao) factory.create(ExecuteServiceDao.class, url);
      
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息