本篇博文远程接口及其实现类代码不再放上来,参考博文Web项目中JAVA RMI实现中的代码
一、服务器端代码
- 建立远程接口,该接口不用再像JAVA RMI中继承Romote类了。
- 建立远程接口的实现类,该类不用再像JAVA RMI中继承java.rmi.UnicastRemoteObject类,构造方法也不需要创建。
- 配置spring配置文件application.xml文件如下:
<!--远程接口实现类--> <bean id="emailService" class="com.jackmouse.rmi.email.service.EmailService"/> <bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter"> <!--服务名--> <property name="service" ref="emailService"></property> <!--serviceName属性用来在RMI注册表中注册一个服务--> <property name="serviceName" value="email"></property> <property name="serviceInterface" value="com.jackmouse.rmi.email.service.IEmailService"/> <property name="registryPort" value="8888"></property> </bean>
- web.xml中配置DispatcherServlet并设置contextConfigLocation值为application.xml
- 发布项目
二、客户端代码
- 创建与服务器端相同的远程接口
- 配置spring配置文件application.xml文件如下:
<bean id="emailService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> // <property name="serviceUrl" value="rmi://127.0.0.1:8888/email"/> <property name="serviceInterface" value="com.jackmouse.rmi.email.service.IEmailService"/> <!-- 预查找远程对象 默认为true --> <property name="lookupStubOnStartup" value="false"/> <!-- 是否刷新远程调用缓存的stub --> <property name="refreshStubOnConnectFailure" value="true"></property> </bean>
- 测试类
package packageofrmi; import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; import com.jackmouse.rmi.email.service.IEmailService; /** * 客户端测试 */ public class TestClient { public static void main(String[] args) { String title = "rmi测试";//邮件主题 String password = "XXX";//发件人密码 String to = "XXXX@qq.com";//收件人邮箱账号 String from = "XXXX@qq.com";//发件人邮箱账号 String content="123";//邮件内容 ApplicationContext ctx =new ClassPathXmlApplicationContext("application.xml"); IEmailService emailService = (IEmailService)ctx.getBean("email"); System.out.println(emailService.send(from,password,title,content,to)); } }
三、注意点
当rmi服务器在远程服务器时,如果远程服务器有多个网卡,就需要指定某个ip。
服务器端需要像JAVA RMI中创建ServletContextListener监听器的子类EmailServiceListener并在contextInitialized方法中写入如下代码
System.setProperty("java.rmi.server.hostname","49.*.*.*");
但是在spring中可以通过配置MethodInvokingFactoryBean进行静态注入来配置某些系统配置,所以在application.xml中加入如下配置即可代替以上代码的作用
<!--静态注入服务器的hostname-->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" value="#{@systemProperties}" />
<property name="targetMethod" value="putAll" />
<property name="arguments">
<props>
<prop key="java.rmi.server.hostname" >远程服务器的公网ip</prop>
</props>
</property>
</bean>
#{@systemProperties}等效于java.lang.System.getProperties()方法返回的Properties对象。
这个配置的通俗理解:在bean的生命周期的初始化阶段,通过SpEL表达式,引用systemProperties的bean,通过MethodInvokingFactoryBean调用引用bean的putAll方法,将所配置的属性(moaLogPath、moaPort…等),注入到System的Properties中。
在idea中发现虽运行时不报错,但编译器一直提示putAll不存在。所以可将上述代码改为
<!--静态注入服务器的hostname-->
<bean id="sysProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.System"/>
<property name="targetMethod" value="getProperties"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="sysProps">
</property>
<property name="targetMethod" value="putAll" />
<property name="arguments">
<props>
<prop key="java.rmi.server.hostname" >远程服务器的公网ip</prop>
</props>
</property>
</bean>