使用Spring构建RMI服务器和客户端

上一篇文章我们实用JDK原生API构造了简单RMI应用,本篇将实用Spring框架来构造RMI的应用,实用Spring你会体验到简单,不需要那么多的条条框框,因为Spring给你做了很多封装。

项目构架

首先看下我的Demo构架图:

示例代码

  1. 远程接口IHello.java

    package net.oseye.DemoSpringRMI.RemotInterface;
    
    /**
     * 远程接口
     * @author oseye
     */
    public interface IHello {
    
    	String sayHello(String name);
    }
    可以看到不用必须继承Remote接口和抛出异常RemoteException了,很简洁吧。
  2. 服务器端和客户端需要在pom.xml(我使用了Maven构建项目,你也可以手动添加依赖)添加Spring的context依赖

    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-context</artifactId>
    	<version>4.0.3.RELEASE</version>
    </dependency>
    它会自动添加相关依赖如:spring-beans等,如下图

    并引用远程接口项目进来,服务器端HelloImpl.java

    package net.oseye.DemoSpringRMI.Server;
    
    import net.oseye.DemoSpringRMI.RemotInterface.IHello;
    
    public class HelloImpl implements IHello {
    	public String sayHello(String name) {
    		return "Hello,"+name;
    	}
    }
    可以看到也不用继承UnicastRemoteObject类了。看下spring的配置文件applicationcontext.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"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    	<bean id="helloService" class="net.oseye.DemoSpringRMI.Server.HelloImpl"></bean>
    	
    	<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
    		<property name="serviceName" value="HelloService"></property>
    		<property name="service" ref="helloService"/>
    		<property name="serviceInterface" value="net.oseye.DemoSpringRMI.RemotInterface.IHello"/>
    		<property name="registryPort" value="1199"/>
    	</bean>
    </beans>
    服务器端使用了org.springframework.remoting.rmi.RmiServiceExporter类,并注入相关属性:serviceName、service、serviceInterface、registryPort等,还有更多的属性可以查看spring类库如:


    主程序App.java

    package net.oseye.DemoSpringRMI.Server;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class App 
    {
        @SuppressWarnings("resource")
    	public static void main( String[] args )
        {
    		new ClassPathXmlApplicationContext("applicationcontext.xml");
        	System.out.println("服务器启动成功");
        }
    }
  3. 客户端同样需要添加spring-context依赖和引用远程接口项目(开发过程中服务器和客户都需要获得远程接口,否则无法进行,远程接口是相互协商的结果),Spring配置文件applicationcontext.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"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    	<bean id="helloService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    	    <property name="serviceUrl" value="rmi://10.9.146.113:1199/HelloService"/>
    	    <property name="serviceInterface" value="net.oseye.DemoSpringRMI.RemotInterface.IHello"/>
    	</bean>
    </beans>
    主程序App.java
    package net.oseye.DemoSpringRMI.Client;
    
    import java.rmi.RemoteException;
    
    import net.oseye.DemoSpringRMI.RemotInterface.IHello;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class App {
    	@SuppressWarnings("resource")
    	public static void main(String[] args) throws RemoteException {
    		ApplicationContext context = new ClassPathXmlApplicationContext(
    				"applicationcontext.xml");
    		IHello stub = (IHello) context.getBean("helloService");
    		System.out.println(stub.sayHello("kevin"));
    	}
    }
  4. 运行
    至此服务器端和客户端开发完成,可以在Eclipse上多窗口运行服务器端和客户端。

    红色报警信息是因为我没有配置log4j。

问题和办法

  • 问题
    客户端和服务器在Eclipse上成功运行,但当我把它们打成可执行Jar的时候,却报告了类似这样的异常

    WARNING: Ignored XML validation warning
    org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 120; schema_reference.4: 无法读取方案文档 'http://www.springframework.org/schema/beans/spring-beans.xsd', 原因为 1) 无法找到文档; 2) 无法读取文档; 3) 文档的根元素不是。

  • 原因
    异常描述得很清楚,是无法读取“http://www.springframework.org/schema/beans/spring-beans.xsd”。
    还记得applicationcontext.xml配置文件吗?它有段是这样的
    <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"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    这得从Xml的命名空间说起,但这里不做展开,我将另起一篇来说说XML,但你需要知道这段的含义
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    它是被空格分开的两段,前一段代表命名空间,后一段代表是与其对应的验证模式。而spring首先是在META-INF/spring.schemas(打好的包里路径)搜索是否有验证模式,如果有直接取本地目录的验证文件;如果没有,就需要通过网络下载。spring.schemas内容类似
    ....
    http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd
    http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd
    http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
    http\://www.springframework.org/schema/lang/spring-lang-4.0.xsd=org/springframework/scripting/config/spring-lang-4.0.xsd
    http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-4.0.xsd
    http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd
    http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd
    http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
    http\://www.springframework.org/schema/task/spring-task-4.0.xsd=org/springframework/scheduling/config/spring-task-4.0.xsd
    .....
    =前边代码命名空间,=号后面代表本地(Jar里)的验证模式文件路径。
    本例异常的原因就清晰了:spring首先在spring.schemas搜索命名空间“http://www.springframework.org/schema/beans/spring-beans.xsd”对应的本地验证模式路径,没有找到,于是去网上下载,但我的PC联不了外网,造成无法读取"http://www.springframework.org/schema/beans/spring-beans.xsd"。
    那么我的eclipse为什么可以运行呢?因为我的Eclipse使用了代理上网。
  • 办法
    1. 在能联公网的情况下运行服务器和客户端;
    2. 建立提供验证模式文件的内部服务,修改host;
    3. 使用本地资源:
      其实命名空间“http://www.springframework.org/schema/beans”在项目引用的“Spring-beans-4.0.3.Release.jar”里的"spring.schemas"中有,而打包后只把“Spring-context-4.0.3.Release.jar”里的"spring.schemas"打到包里了,估计是因为两个重名吧。查看“Spring-beans-4.0.3.Release.jar”里的"spring.schemas"可以看到:
      http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsd
      于是使用classpath把验证模式指向本地,修改如下:
      <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"
      	xsi:schemaLocation="http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-4.0.xsd
      		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

重新打包即可。关于命名空间的深入讨论请点击这里:《Java使用Schema模式对XML验证》

转载于:https://www.cnblogs.com/zhaiqianfeng/p/4620373.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值