A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大山哥哥 于 2018-5-12 21:45 编辑

    在工作中经常会遇到两个项目间进行信息交互的业务,在黑马课程中,提到过搭建webservice服务的方式来提供信息,下面将介绍另外一种通信技术java的RMI(Remote Method Invocation),java远程方法调用。
它让客户端远程调用服务的时候就和调用本地项目一般,只不过客户端只能看到服务端注册发布的服务接口。本案例将使用spring整合RMI完成服务端的开发和客户端的调用。
    需求如下:
  • 客户端向服务端发送“你好”,服务端给客户端回馈信息。
  • 客户端向服务端请求用户(User)列表数据,服务端直接返回张三、李四用户。
   【第一步】搭建服务端
  • [1]准备maven项目,导入基本的jar依赖如下:
[XML] 纯文本查看 复制代码
<dependencies>
          <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>4.2.8.RELEASE</version>
          </dependency>
          <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-beans</artifactId>
                  <version>4.2.8.RELEASE</version>
          </dependency>
          <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-web</artifactId>
                  <version>4.2.8.RELEASE</version>
          </dependency>
          <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
          </dependency>
          <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-test</artifactId>
                  <version>4.2.8.RELEASE</version>
          </dependency>
  </dependencies>

  • [2]准备基本的POJO类User如下:
[Java] 纯文本查看 复制代码
public class User implements Serializable {
        
        private static final long serialVersionUID = -999055038502751118L;
        private Integer id;
        private String username;
        private String password;
        public User() {
        }
        
        public User(Integer id, String username, String password) {
                this.id = id;
                this.username = username;
                this.password = password;
        }

        //...省略getter setter方法
        
        @Override
        public String toString() {
                return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
        }
        

}

注意,User类需要实现序列化接口

  • [3]准备服务接口如下:
[Java] 纯文本查看 复制代码
public interface UserService{
        
        public String sayHello(String msg);
        
        public List<User> getAllUsers();
}

接口没有特殊的要求


  • [4]准备接口实现类如下:   
[Java] 纯文本查看 复制代码
@Service
public class UserServiceImpl implements UserService{

        @Override
        public String sayHello(String msg) {
                System.out.println("服务端收到的消息是:"+msg);
                return "答复如下:您的消息【"+ msg +"】已收到";
        }
        @Override
        public List<User> getAllUsers() {
                List<User> users = new ArrayList<User>();
                User san = new User(1, "张三", "123");
                User si = new User(2, "李四", "456");
                users.add(san);
                users.add(si);
                return users;
        }
}

在实现类上添加了一个@Service注解,为的是在下面的测试类中直接注入使用


  • [5]配置服务--需要将接口注册到网络
[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:aop="http://www.springframework.org/schema/aop" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                [url=http://www.springframework.org/schema/beans/spring-beans-4.0.xsd]http://www.springframework.org/schema/beans/spring-beans-4.0.xsd[/url] 
                [url=http://www.springframework.org/schema/context]http://www.springframework.org/schema/context[/url] 
                [url=http://www.springframework.org/schema/context/spring-context-4.0.xsd]http://www.springframework.org/s ... ing-context-4.0.xsd[/url] 
                [url=http://www.springframework.org/schema/aop]http://www.springframework.org/schema/aop[/url] 
                [url=http://www.springframework.org/schema/aop/spring-aop-4.0.xsd]http://www.springframework.org/schema/aop/spring-aop-4.0.xsd[/url]">

        <!-- 配置  扫描   @Service -->
        <context:component-scan base-package="com.itheima.rmi.service"/>
        
        <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
                <property name="serviceName" value="userServer"/><!-- 暴露的服务名 -->
                <property name="service" ref="userServiceImpl"/><!-- 服务类 -->
                <property name="serviceInterface" value="com.itheima.rmi.service.UserService"/><!-- 暴露出去的接口 -->
                <property name="registryPort" value="9001"/><!-- 暴露发布到网络的端口,供客户端访问 -->
        </bean>
</beans>

  • [6]开启服务--在测试类中让spring加载主配置文件,并让线程不关闭即可
[Java] 纯文本查看 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class RmiServer {

        @Test
        public void runServer() {
                while(true) {
                        
                }
        }
}



会在控制台中看到日志记录:
[Java] 纯文本查看 复制代码
信息: Looking for RMI registry at port '9001'
信息: Binding service 'userServer' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[192.168.111.1:9001](local),objID:[0:0:0, 0]]]]

服务发布成功!


接下来,使用客户端访问这两个接口(sayHello、getAllUsers)
开始客户端的配置使用:
  • [1]从服务端将User类和UserService接口完整的拿过来,保持包路径不变(可以让服务方将这两个类打包,因为在使用时,类和接口的引用路径要和服务端完全一致)。
  • [2]配置客户端的主配置文件
[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:aop="http://www.springframework.org/schema/aop" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                [url=http://www.springframework.org/schema/beans/spring-beans-4.0.xsd]http://www.springframework.org/schema/beans/spring-beans-4.0.xsd[/url] 
                [url=http://www.springframework.org/schema/context]http://www.springframework.org/schema/context[/url] 
                [url=http://www.springframework.org/schema/context/spring-context-4.0.xsd]http://www.springframework.org/s ... ing-context-4.0.xsd[/url] 
                [url=http://www.springframework.org/schema/aop]http://www.springframework.org/schema/aop[/url] 
                [url=http://www.springframework.org/schema/aop/spring-aop-4.0.xsd]http://www.springframework.org/schema/aop/spring-aop-4.0.xsd[/url]">
        
        <!-- RmiProxyFactoryBean代理配置中的接口并通过远程访问服务端公布的服务地址调用接口中的方法  -->
        <bean id="userServer" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">  
                <property name="serviceUrl">
                        <!-- ip为服务端提供的ip。端口对应服务端的registryPort -->
                        <value>rmi://192.168.111.1:9001/userServer</value>
                </property>
                <!-- 配置要代理的接口 -->
                <property name="serviceInterface" value="com.itheima.rmi.service.UserService">
                </property>  
        </bean>
</beans>

  • [3]开发测试类,调用接口中的方法
[Java] 纯文本查看 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class RmiClientTest {
        
        //直接注入UserService类型的bean 即可使用
        @Autowired
        @Qualifier("userServer")
        private UserService user;
        
        @Test
        public void testRmi1() {
                String sayHello = user.sayHello("你好");
                System.out.println("[客户端接收到的回复消息]||" + sayHello);
                List<User> getAllUsers = user.getAllUsers();
                System.out.println(getAllUsers);
        }
}

  • [4]查看打印接口
[Java] 纯文本查看 复制代码
[客户端接收到的回复消息]||答复如下:您的消息【你好】已收到
[User [id=1, username=张三, password=123], User [id=2, username=李四, password=456]]

可以看到,后台已成功获取服务端的消息内容。
具体代码可以下载附件文件进行运行,注意,在下载之后记得更改客户端的ip访问地址。
RMI.zip (44.7 KB, 下载次数: 25)




2 个回复

倒序浏览
我来占层楼啊   
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马