前言
上篇实现了rmi远程跨JVM调用service,但是感觉很鸡肋吧!不能每个接口都单独注册一个RMI路径呀,太累了。所以这篇呢,会将rmi和spring集成起来,通过rmi实现远程反射调用spring容器中的其他接口。
准备工作
修改pom文件
<!-- spring支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.30</version>
</dependency>
要实现的效果
消费者通过远程rmi协议调用提供者内部的UserService接口(提供者只暴露RmiService服务)
代码实现
通用接口
- 新建RmiService接口
package com.zyu.service;
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Map;
/**
* rmi远程服务接口,可以远程调用提供者的内部方法
*/
public interface RmiService extends Remote, Serializable {
final String REMOTE_URL = "rmi://127.0.0.1:9080/RmiService";
final int port = 9080;
/**
* 远程调用的方法信息
* @param info 对象,方法,参数
* @return
*/
Object remoteInvoke(Map<String,Object> info) throws RemoteException;
}
- 新建UserService接口
package com.zyu.service;
public interface UserService {
String echoUser(String username);
}
Provider端实现
- 实现RmiService接口
package com.zyu.service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;
public class RmiServiceImpl extends UnicastRemoteObject implements RmiService {
protected RmiServiceImpl() throws RemoteException {
}
public Object remoteInvoke(Map<String, Object> info) throws RemoteException {
return null;
}
}
- 实现UserService接口
package com.zyu.service;
public class UserServiceImpl implements UserService {
public String echoUser(String username) {
return "hello," + username;
}
}
- 反射工具类
package com.zyu.utils;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
/**
* 反射工具类
*/
public class InvokeUtils {
/**
* 根据传递的方法信息,反射调用spring容器中的方法
*
* @param info
* @param app
* @return
*/
public static Object call(Map<String, Object> info, ApplicationContext app) {
String targetName = (String) info.get("target");
String methodName = (String) info.get("method");
Object[] args = (Object[]) info.get("args");
Class<?>[] argTypes = new Class[args.length];
int i = 0;
for (Object arg : args) {
argTypes[i++] = arg.getClass();
}
return call(app.getBean(targetName), methodName,argTypes,args);
}
/**
* java反射
*
* @param target 调用的目标对象
* @param methodName 方法名
* @param argTypes 方法参数列表类型
* @param args 方法参数列表
* @return
*/
public static Object call(Object target, String methodName, Class<?>[] argTypes, Object[] args) {
try {
Method method = target.getClass().getMethod(methodName, argTypes);
return method.invoke(target, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
}
- 服务暴露
package com.zyu;
import com.alibaba.fastjson.JSON;
import com.zyu.service.RmiService;
import com.zyu.service.RmiServiceImpl;
import com.zyu.service.UserService;
import com.zyu.service.UserServiceImpl;
import com.zyu.utils.InvokeUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Map;
/**
* 服务提供者,通过rmi协议暴露spring中相关的服务
*/
public class Provider {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Config.class);
app.start();
System.out.println("spring容器启动成功");
initRmiProtocol(app);
System.in.read();
}
/**
* 开放rmi调用协议
* @param app
*/
public static void initRmiProtocol(final AnnotationConfigApplicationContext app) throws RemoteException {
RmiService rmiService = new RmiServiceImpl() {
@Override
public Object remoteInvoke(Map<String, Object> info) throws RemoteException {
Object result = InvokeUtils.call(info, app);
System.out.println("方法调用成功,返回值:"+ JSON.toJSONString(result));
return result;
}
};
try {
//绑定端口
LocateRegistry.createRegistry(RmiService.port);
//绑定url
Naming.bind(RmiService.REMOTE_URL,rmiService);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
System.out.println("开放rmi协议。。。");
}
@Configuration
static class Config{
@Bean
public UserService userService(){
return new UserServiceImpl();
}
}
}
Consumer端实现
两种调用方式:
- 自己组装反射的调用信息
- 使用静态代理,封装反射信息
package com.zyu;
import com.alibaba.fastjson.JSON;
import com.zyu.service.RmiService;
import com.zyu.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
public class Consumer {
public static void main(String[] args) {
//启动spring容器
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Config.class);
app.start();
//获取远程调用服务
RmiService rmiService = app.getBean(RmiService.class);
//调用方式1:手动组装要调用的信息
Map<String, Object> info = new HashMap<String, Object>();
info.put("target", "userService");
info.put("method", "echoUser");
info.put("args", new Object[]{"zyufocus"});
try {
Object ret = rmiService.remoteInvoke(info);
System.out.println(JSON.toJSONString(ret));
} catch (RemoteException e) {
e.printStackTrace();
}
//调用方式2:静态代理封装
UserService userService = getService(rmiService);
String result = userService.echoUser("zyufocus2");
System.out.println("static proxy remote invoke,result:" + result);
}
//使用静态代理,自动封装需要反射的参数信息
private static UserService getService(final RmiService rmiService) {
return new UserService() {
public String echoUser(String username) {
//组装要调用的信息
Map<String, Object> info = new HashMap<String, Object>();
info.put("target", "userService");
info.put("method", "echoUser");
info.put("args", new Object[]{username});
try {
return (String) rmiService.remoteInvoke(info);
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
};
}
static class Config {
@Bean
public RmiService rmiService() {
RmiService rmiService = null;
try {
rmiService = (RmiService) Naming.lookup(RmiService.REMOTE_URL);
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
return rmiService;
}
}
}
测试
-
启动Provider
-
启动Consumer
消费者
提供者
结束语
感觉有点意思,开心
学无止境,诸君共勉