Java Spring RMI一些尝试

简介: 最近在做一个调度服务器的项目,因为各个服务器上面的定时任务比较多,分别执行的话运维检查起来比较麻烦.就想到搞一个专门的调度服务器来统一管理这些任务.因为随时可能增加新的服务器或者新的命令,要是全写在一起每次要把整个程序替换掉,上线不方便.

最近在做一个调度服务器的项目,因为各个服务器上面的定时任务比较多,分别执行的话运维检查起来比较麻烦.就想到搞一个专门的调度服务器来统一管理这些任务.因为随时可能增加新的服务器或者新的命令,要是全写在一起每次要把整个程序替换掉,上线不方便.发现spring可以很好的解决这个问题,新加的程序可以以单独jar包的方式添加,只需要修改ApplicationContext就行了,client端只需要改配置就行了程序可以不用改.个人感觉spinrg自身的RMI类比Java自带的好理解一些.

首先是Server端,需要有一个启动函数,以及各命令对应的实现接口,启动类 .为了部署方便期间,配置文件路径直接改外部输入了

public class StartRMIServer {
    public static void startRMIServer(String path) {
        if(path != null && path.startsWith("/")) {
            new FileSystemXmlApplicationContext("/" + path + "applicationContext.xml");
        }else{
            new FileSystemXmlApplicationContext(path + "applicationContext.xml");
        }
        System.out.println("RMI服务端启动!!!");
    }

    public static void main(String[] args) {
        startRMIServer(args[0]);
    }
}

 关于FileSystemXmlApplicationContext这里一开始不知道,在Linux下输入的根路径会被当成当前路径处理,去查了之后发现是构造函数会把第一个'/'给去掉,所以这里需要加上.也可以用ClassPathXmlApplicationContext直接以file:开头

然后加入接口和实现类,当客户端发起命令时就会调用该接口,接口对应的实现类由spring定义文件来控制,所以就能够实现不同的命令对应不同的实现类.这里定义了两个不同的实现类

public interface IRmiService{
    String getMsg(String params) throws Exception;
}

 调用的类预留一个字符串参数,便于有需要的实现类解析后使用

public class HelloWordService implements IRmiService{
    public String getMsg(String params) throws Exception{
        return "Hello World!"; 
    }
}


public class RealTimeService implements IRmiService {
    public String getMsg(String params){
        return "Real Time!" +  params; 
    }
}

ApplicationContext配置定义如下,两个实现类分别对应不同的命令

   <!-- 定义接口实现类 --> 
    <bean id="helloWordService" class="com.cmb.SpringRmi.HelloWordService" scope="prototype"/> 
   
   <!-- 定义服务端接口 -->
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
        <!-- 将远程接口实现类对象设置到RMI服务中 -->
        <property name="service" ref="helloWordService" />
        <!-- 设置RMI服务名,将作为RMI客户端的调用接口-->
        <property name="serviceName" value="helloWord" />
        <!-- 将远程接口设置为RMI服务接口 -->
        <property name="serviceInterface" value="com.cmb.SpringRmi.IRmiService" />
        <!-- 为RMI服务端远程对象注册表设置端口号-->
        <property name="registryPort" value="9090" />
    </bean>

   <bean id="realTimeService" class="com.cmb.SpringRmi.RealTimeService" scope="prototype"/>
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="realTimeService" />
        <property name="serviceName" value="realTime" />
        <property name="serviceInterface" value="com.cmb.SpringRmi.IRmiService" />
        <property name="registryPort" value="9090" />
    </bean>

 这样server端就配置完成了,可以直接启动试一下

 

client端相当于是每次给server发一个请求命令,server端接收到之后去执行对应的实现类.我这边实现类加了log4j功能,参数是context路径,命令和命令对应的参数

public class RMIClient {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("file:" + args[0] + "/applicationContext.xml");
        IRmiServer helloWord = (IRmiServer) ctx.getBean(args[1]);
        LogBean log = (LogBean) ctx.getBean("log");
        PropertyConfigurator.configure(log.getPath());
        Logger logger = Logger.getLogger(RMIClient.class);
        logger.info("Call " + args[1]);
        try {
            String params = "";
            if (args.length > 2 && args[2] != null && !"".equals(args[2])) {
                params = args[2];
            }
            logger.info(helloWord.getMsg(params));
            logger.info(args[1] + " succeed");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            System.exit(1);
        }
    }
}

 接口名字其实不需要和server端一样

public interface IRmiServer{
    String getMsg(String params) throws Exception;
}

spring设置如下,这里设置了两条命令helloWorld和printDate,分别对应类HelloWordService和RealTimeService

    <!--bean id为程序调用时输入的第一参数-->    
    <bean id="helloWord" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> 
        <!--ip和端口为server的ip和刚才注册的端口号,服务名为设置的serviceName-->
        <property name="serviceUrl" value="rmi://localhost:9090/helloWord"/>
        <!--调用的接口-->
        <property name="serviceInterface" value="com.cmb.SpringRmiClient.IRmiServer"/>
        <!-- 当连接失败时是否刷新远程调用stub -->
        <property name="refreshStubOnConnectFailure" value="true"/>
    </bean>
    
    <bean id="printDate" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> 
        <property name="serviceUrl" value="rmi://localhost:9090/realTime"/>
        <property name="serviceInterface" value="com.cmb.SpringRmiClient.IRmiServer"/>
        <property name="refreshStubOnConnectFailure" value="true"/>
    </bean>

此时就可以执行client,可以看到如果输入的命令不同,打印出的结果是不同的,说明调用的实现类不同.

部署的时候采用命令行指定java.ext.dirs的方式,这样可以把所有相关的程序jar包都放到文件夹里面,便于后续扩展程序的部署.

java -Djava.ext.dirs="rmiclient/lib" -jar rmiclient/rmiclient.jar D:/test/rmiclient printDate

关于后续添加部署.我现在想要添加一个程序,那么应该把这个jar包放置到server上的lib目录中,把server进程结束,然后在server的ApplicationContext增加一组bean,client的ApplicationContext也对应增加一组,重启之后就可以使用新的程序了.

 通过这个小工具的开发对spring工厂和IOC有了些了解,后面要多研究吃透spring

个人GitHub地址: https://github.com/GrayWind33
相关文章
|
30天前
|
安全 前端开发 Java
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择。依赖注入使对象管理交由Spring容器处理,实现低耦合高内聚;AOP则分离横切关注点如事务管理,增强代码模块化。Spring还提供MVC、Data、Security等模块满足多样需求,并通过Spring Boot简化配置与部署,加速微服务架构构建。掌握这些核心概念与工具,开发者能更从容应对挑战,打造卓越应用。
32 1
|
4天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
4天前
|
缓存 Java 数据库
【Java面试题汇总】Spring篇(2023版)
IoC、DI、aop、事务、为什么不建议@Transactional、事务传播级别、@Autowired和@Resource注解的区别、BeanFactory和FactoryBean的区别、Bean的作用域,以及默认的作用域、Bean的生命周期、循环依赖、三级缓存、
【Java面试题汇总】Spring篇(2023版)
|
5天前
|
Java 数据库连接 API
【Java笔记+踩坑】Spring Data JPA
从常用注解、实体类和各层编写方法入手,详细介绍JPA框架在增删改查等方面的基本用法,以及填充用户名日期、分页查询等高级用法。
【Java笔记+踩坑】Spring Data JPA
|
5天前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
27天前
|
IDE Java 开发工具
快速上手指南:如何用Spring Boot开启你的Java开发之旅?
【8月更文挑战第22天】Spring Boot由Pivotal团队开发,简化了Spring应用的创建过程。本文详述了从零开始搭建Spring Boot项目的步骤:首先确保安装了新版JDK、Maven/Gradle及IDE如IntelliJ IDEA或Eclipse;接着访问Spring Initializr网站(start.spring.io),选择所需依赖(如Web模块)并生成项目;最后,使用IDE打开生成的项目,添加`@SpringBootApplication`注解及main方法来启动应用。通过这些步骤,即便是新手也能快速上手,专注于业务逻辑的实现。
32 1
|
29天前
|
Java API 数据库
详细介绍如何使用Spring Boot简化Java Web开发过程。
Spring Boot简化Java Web开发,以轻量级、易用及高度可定制著称。通过预设模板和默认配置,开发者可迅速搭建Spring应用。本文通过创建RESTful API示例介绍其快速开发流程:从环境准备、代码编写到项目运行及集成数据库等技术,展现Spring Boot如何使Java Web开发变得更高效、简洁。
40 1
|
17天前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
27 0
|
17天前
|
Java Spring 开发者
Java Web开发新潮流:Vaadin与Spring Boot强强联手,打造高效便捷的应用体验!
【8月更文挑战第31天】《Vaadin与Spring Boot集成:最佳实践指南》介绍了如何结合Vaadin和Spring Boot的优势进行高效Java Web开发。文章首先概述了集成的基本步骤,包括引入依赖和配置自动功能,然后通过示例展示了如何创建和使用Vaadin组件。相较于传统框架,这种集成方式简化了配置、提升了开发效率并便于部署。尽管可能存在性能和学习曲线方面的挑战,但合理的框架组合能显著提升应用开发的质量和速度。
26 0
|
20天前
|
安全 Java 开发者
Java反射:Spring Boot背后的魔法,让你的代码质量飞跃的神秘力量!
【8月更文挑战第29天】Java反射机制允许程序在运行时访问和修改类、接口、方法等属性,而Spring Boot则广泛应用反射实现依赖注入和自动配置。本文探讨如何利用反射机制提升Spring Boot应用的代码质量,包括动态类型处理、元数据访问及依赖注入等方面。通过实战示例展示动态调用方法和自定义注解处理,强调反射机制对代码灵活性与扩展性的贡献,同时提醒开发者注意性能和安全问题。
35 0