【JAVA使用笔记】——SpringBoot启动方式及远程调用(三)

本文通过一个具体的实例,详细介绍了如何使用RMI在多模块间的Spring Boot应用中进行远程方法调用,包括服务端的接口定义、实现与暴露,以及客户端的代理创建与方法调用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇:https://blog.youkuaiyun.com/NEU_LightBulb/article/details/102892314

四、以RMI为例的多模块间方法调用

1. Pre

        RMI、Hessian和Spring HttpInvoker的使用逻辑基本相同:

        编写服务端的方法接口与实现 >> 注册到对应的代理中暴露服务 >> 客户端同URL+唯一标识加载对应代理中的方法 >> 客户端调用。

 

2. 样例工程结构

        在rmi工程中建立两个模块rmi-server和rmi-client。其中rmi-server是一个无Web的SpringBoot并引入Mybatis等依赖,而rmi-server是一个除Spring外没有其他依赖的含Web的SpringBoot工程。

        具体怎么建立多模块程序,参考 https://blog.youkuaiyun.com/zcf980/article/details/83040029

3.实现功能

        服务端启动时加载数据源表中全部数据到一个List,之后会启动一个线程实时(每隔3秒)打印List内信息。同时服务端提供一个update的接口可以根据id更新List中和数据源表中的value。

4.代码

/**
 * Server 启动类
 */
@SpringBootApplication
public class RmiServerApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(RmiServerApplication.class)
                .web(WebApplicationType.NONE) // 设置为非 WEB
                .run(args);
    }

}
/**
 * Server服务类同时也是远程接口实现类
 */
@Service
public class InfoService implements InfoRMI{

    @Autowired
    InfoMapper infoMapper;
    @Autowired
    InfoLogic infoLogic;

    /**
     * 实现远程接口
     * @param id info对象ID
     * @param value info对象值
     * @throws RemoteException
     */
    @Override
    public void updateInfoValueById(String id,Integer value) throws RemoteException {
        infoLogic.updateValueById(id,value);
        infoMapper.setInfoValueById(value,id);
    }

    /**
     * 初始化逻辑类内数据对象启动逻辑线程
     */
    public void initIdList(){
        List<Info> infoList = infoMapper.getInfos();
        infoLogic.initIdList(infoList);
        infoLogic.start();
    }
    
}
/**
 * Server远程方法接口
 */
public interface InfoRMI extends Remote {
    public void updateInfoValueById(String id, Integer value) throws RemoteException;
}

        省略Info对象定义以及Mapper定义

/**
 * Server逻辑的启动类,在 Server启动后执行
 */
@Component
public class Starter implements CommandLineRunner {

    @Autowired
    InfoService infoService;

    @Override
    public void run(String... args) throws Exception {
        infoService.initIdList();
    }
}
/**
 * Server逻辑类
 */
public class InfoLogic implements AutoCloseable{

    private final ArrayList<Info> infos = new ArrayList<>();
    private final Logic logic;

    //初始化
    public InfoLogic() {
        this.logic = new Logic();
    }
    //启动
    public void start(){
        this.logic.start();
    }
    //初始化数据对象
    public void initIdList(List<Info> list){
        this.infos.addAll(list);
    }
    //更新数据对象方法
    public void updateValueById(String id,Integer value){
        for (Info item : this.infos){
            if(item.getId().equals(id)){
                item.setValue(value);
                item.setUpdate(new Date());
            }
        }
    }

    @Override
    public void close() throws Exception {
        this.logic.stop();
    }

    //逻辑线程
    private class Logic extends Thread{
        @Override
        public void run() {
            while (true){
                System.out.println("#====================================================================#");
                for (Info item : infos){
                    System.out.println(item.toString());
                }
                try {
                    sleep(3000);
                }catch (InterruptedException e){
                    continue;
                }
            }
        }
    }
}
/**
 * Server 配置类
 */
@Configuration
@ComponentScan("com.example.rmiserver")
public class Configure {

    @Autowired
    private InfoService infoService;

    //加入 RmiServiceExporter并把接口及接口实现类注册
    @Bean
    public RmiServiceExporter rmiServiceExporter(){
        RmiServiceExporter exporter = new RmiServiceExporter();
        exporter.setServiceInterface(InfoRMI.class);
        exporter.setServiceName("infoService");
        exporter.setService(infoService);
        exporter.setServicePort(6789);
        exporter.setRegistryPort(1234);
        return exporter;
    }

    //注册逻辑类
    @Bean
    @ConditionalOnClass(InfoLogic.class)
    public InfoLogic infoLogic() {
        return new InfoLogic();
    }
}
/**
 * Client启动类
 */
@SpringBootApplication
public class RmiClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(RmiClientApplication.class, args);
    }

}
/**
 * Client方法接口定义,不需要实现类
 */
public interface InfoRMI {
    public void updateInfoValueById(String id,Integer value);
}
/**
 * Client 配置类
 */
@Configuration
public class Configure {

    //加入RmiProxyFactoryBean 代理
    @Bean(name = "infoService")
    public RmiProxyFactoryBean rmiProxyFactoryBean(){
        RmiProxyFactoryBean rmiProxyFactoryBean=new RmiProxyFactoryBean();
        rmiProxyFactoryBean.setServiceInterface(InfoRMI.class);
        rmiProxyFactoryBean.setServiceUrl("rmi://localhost:1234/infoService");
        return rmiProxyFactoryBean;
    }
}
/**
 * Client web controller
 */
@Controller
public class InfoController {

    @Autowired
    @Qualifier("infoService")
    private RmiProxyFactoryBean rmiBean;

    @ResponseBody
    @RequestMapping("/update/{id}/{value}")
    public String update(@PathVariable String id, @PathVariable Integer value) throws Exception{
        //使用远程接口
        InfoRMI infoService = (InfoRMI)rmiBean.getObject();
        infoService.updateInfoValueById(id,value);
        return "DONE";
    }
}

5.测试

        先启动Server,再启动Client,Server控制台开始打印

        浏览器或Postman测试API : http://localhost:8080/update/1024003/6789

        Server控制台打印结果

上一篇:https://blog.youkuaiyun.com/NEU_LightBulb/article/details/102892314

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值