前提:
1.开发工具:
jdk tomcat ecplise,开发工具的使用本篇不做介绍。
2.需具备以下知识:javase servelt web rmi spring maven
一、关于RMI
请参考另外一篇文章:https://www.cnblogs.com/liandy001/p/11182055.html
二、Spring的远程技术
- 远程方法调用(RMI):通过使用 RmiProxyFactoryBean 和 RmiServiceExporter,Spring同时支持传统的RMI(使用 java.rmi.Remote接口和java.rmi.RemoteException)和通过RMI调用器实现的透明远程调用(支持任何Java接口)。
- Spring的HTTP调用器:Spring提供了一种特殊的允许通过HTTP进行Java串行化的远程调用策略,支持任意Java接口(就像RMI调用器)。相对应的支持类是 HttpInvokerProxyFactoryBean和 HttpInvokerServiceExporter。
- Hessian:通过 HessianProxyFactoryBean 和 HessianServiceExporter,可以使用Caucho提供的基于HTTP的轻量级二进制协议来透明地暴露服务。
- Burlap:待补充。
- JAX RPC:待补充。
- JMS:待补充。
三、服务端
服务端我们采用常见的web应用(当然普通应用也是一样的),web应用在tomcat服务器启动后,通过DispatcherServlet初始化spring容器,创建远程对象并在注册表注册。
1.创建web应用
2.通过maven管理项目的jar包
3.配置pom依赖的jar包
<properties> <spring.version>4.0.2.RELEASE</spring.version> <mybatis.version>3.2.8</mybatis.version> <slf4j.version>1.7.12</slf4j.version> <log4j.version>1.2.17</log4j.version> </properties> <dependencies> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <!-- 表示开发的时候引入,发布的时候不会加载此包 --> <scope>test</scope> </dependency> <!-- java ee包 --> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> </dependency> <!-- spring框架包 start --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <!-- spring框架包 end --> <!-- mybatis框架包 start --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.2</version> </dependency> <!-- mybatis框架包 end --> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> </dependency> <!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!-- jstl标签类 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- log start --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- log END --> <!-- Json --> <!-- 格式化对象,方便输出日志 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.6</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> <!-- 上传组件包 start --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <!-- 上传组件包 end --> <!-- AL相关添加 --> <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency> </dependencies>
4.创建域模型及service
/** * @Title: Fruit.java * @Package cn.com.kamfu * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月13日 下午10:21:02 * @version V1.0 */ package cn.com.kamfu; import java.io.Serializable; import java.util.Date; /** * @ClassName: Fruit * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月13日 下午10:21:02 * */ public class Fruit implements Serializable{ private static final long serialVersionUID = 1883838732853579826L; Integer id;//编号 String name;//名称 Double weight;//重量 String color;//颜色 Date pickDay;//采摘日期 public Fruit() { super(); } public Fruit(Integer id, String name, Double weight, String color, Date pickDay) { super(); this.id = id; this.name = name; this.weight = weight; this.color = color; this.pickDay = pickDay; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public Date getPickDay() { return pickDay; } public void setPickDay(Date pickDay) { this.pickDay = pickDay; } @Override public String toString() { return "Fruit [id=" + id + ", name=" + name + ", weight=" + weight + ", color=" + color + ", pickDay=" + pickDay + "]"; } }
/** * @Title: IService.java * @Package cn.com.kamfu * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月13日 下午10:21:39 * @version V1.0 */ package cn.com.kamfu; /** * @ClassName: IService * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月13日 下午10:21:39 * */ public interface IService { String eat(String fruitName); String eat(Fruit fruit); }
/** * @Title: Service.java * @Package cn.com.kamfu * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月13日 下午10:22:02 * @version V1.0 */ package cn.com.kamfu; /** * @ClassName: Service * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月13日 下午10:22:02 * */ public class Service implements IService { /** * <p>Title: eat</p> * <p>Description: </p> * @param fruitName * @return * @see cn.com.kamfu.IService#eat(java.lang.String) */ @Override public String eat(String fruitName) { // TODO Auto-generated method stub System.out.println("begin------"); System.out.println("i'm eating"+ fruitName ); System.out.println("end------"); return "service ha eaten " + fruitName; } /** * <p>Title: eat</p> * <p>Description: </p> * @param fruit * @return * @see cn.com.kamfu.IService#eat(cn.com.kamfu.Fruit) */ @Override public String eat(Fruit fruit) { // TODO Auto-generated method stub System.out.println("begin------"); System.out.println("i'm eating"+fruit); System.out.println("end------"); return "service has eaten "+ fruit; } }
5.在类目录下创建spring容器
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- 人接口 --> <bean id="service" class="cn.com.kamfu.Service"/> <bean name="/service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <property name="service" ref="service" /> <property name="serviceInterface" value="cn.com.kamfu.IService" /> </bean> </beans>
6.web.xml中初始化spring容器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SpringRMIServer</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/remote-service.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
7.导出jar包(客户端依赖)
一直next,直至Finish,命名为service.jar并保存到本地。
8.项目总体结构
四、客户端
1.创建普通Java应用程序
2.通过maven管理项目的jar包
3.配置pom依赖的jar包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>SpringRMIClient</groupId> <artifactId>SpringRMIClient</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-acl</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-cas</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.2.21.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>4.2.21.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.3.2.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.20</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>3.0.2.RELEASE</version> </dependency> </dependencies> </project>
4.导入服务jar包(service.jar)
5.创建Spring容器
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="service" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"> <property name="serviceUrl"> <value>http://localhost:8080/SpringRMIServer/service</value> </property> <property name="serviceInterface"> <value>cn.com.kamfu.IService</value> </property> </bean> </beans>
6.编写主程序
/** * @Title: App.java * @Package cn.com.kamfu * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月13日 下午10:10:04 * @version V1.0 */ package cn.com.kamfu; import java.util.Date; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @ClassName: App * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月13日 下午10:10:04 * */ public class App { public static ApplicationContext context = new ClassPathXmlApplicationContext("remote-client-local.xml"); /** * @Title: main * @Description: TODO(这里用一句话描述这个方法的作用) * @param: @param args * @return: void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub eatFruit1(); eatFruit2(); } public static void eatFruit1() { IService service = (IService) context.getBean("service"); String response = service.eat("苹果"); System.out.println(response); } public static void eatFruit2() { IService service = (IService) context.getBean("service"); Fruit fruit = new Fruit(1,"西瓜",2.2d,"green",new Date()); String response = service.eat(fruit); System.out.println(response); } }
五、模拟客户端远程访问服务端
1.启动Server端web应用
2.查看控制台tomcat是否启动成功
3.启动Client端访问Server端
4.通过客户端控制台console可以查看到方法成功被调用。