上一篇: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