最近为了学习dubbo照着网上怼了一个简单demo与大家分享
版本
jdk11,dubbo为阿里版,zookeeper3.4,目前是在windows下使用
zookeeper环境详见本人另一篇文章
windows安装zookeeper
apacheDubbo见本人另一篇文章
springboot整合dubbo
一、RPC
远程方法调用,就是像调用本地方法一样调用远程方法
二、上代码
1.dubboInterface主要存放接口和实体类,pom文件没有什么依赖
接口
1.RpcInvoker
这个是消费者和生产者的的共同接口
public interface RpcInvoker {
ApiResult invoke(ApiResult tingContext);
ApiResult asyncInvoke(ApiResult tingContext);
}
2 UserService 这个接口不允许直接调用,通过RpcInvoker的实现类来反射调用
public interface UserService {
User getUserRoleByUser(User user);
User getUserById(Integer uid);
}
实现类和实体类
1.实体类
//用户类
public class User implements Serializable {
private static final long serialVersionUID = 3570930855800498567L;
private Integer id;//用户ID
private Integer age;//用户年龄
private String sex;//用户性别
private String name;//用户姓名
private List<Role> roles;//用户角色集合
}
//角色类
public class Role implements Serializable {
private static final long serialVersionUID = -2328451803818677889L;
private Integer id;//角色id
private String name;//角色名称
private String desc;//角色描述
}
//vo类,这里省略get和set方法
public class ApiResult implements Serializable {
private static final long serialVersionUID = -2328451803818677569L;
/**
* 状态码
*/
private Integer code;
/**
* 返回消息
*/
private String msg;
/**
* 返回实体
*/
private Object object;
/**
* 用来接收参数
*/
private Map<String,Object> map;
}
2.实现类
public class UserServiceImpl implements UserService {
@Override
public User getUserRoleByUser(User user) {
if(user.getId()==null)throw new RuntimeException("用户id不可为空");
System.out.println("正在查询数据库");
Role role1 = new Role();role1.setId(1);role1.setName("财务");role1.setDesc("发工资的");
Role role2 = new Role();role2.setId(2);role2.setName("hr");role2.setDesc("招人的");
Role role3 = new Role();role3.setId(3);role3.setName("开发");role3.setDesc("写代码的");
ArrayList<Role> roles = new ArrayList<>();
roles.add(role1);roles.add(role2);roles.add(role3);
user.setRoles(roles);
System.out.println("查询完毕,总共三条结果");
return user;
}
}
public class RpcInvokerImpl implements RpcInvoker {
/**
* 反射接收 类名、方法名、参数
* @param apiResult
* @return
*/
@Override
public ApiResult invoke(ApiResult apiResult) {
Map<String, Object> map = apiResult.getMap();
String className = (String)map.get("className");
String methodName = (String)map.get("methodName");
Object param = map.get("param");
Object obj = null;
try {
Class clazz = Class.forName(className);
//Method method = clazz.getMethod(methodName);
Method[] methods = clazz.getMethods();
//获取方法
Method method = Arrays.stream(methods).filter(m->m.getName().equals(methodName)).findAny().get();
Object o = clazz.getConstructors()[0].newInstance();
//反射执行
obj = method.invoke(o, param);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//返回结果
apiResult.setObject(obj);
return apiResult;
}
//异步目前的操作一样
@Override
public ApiResult asyncInvoke(ApiResult apiResult) {
Map<String, Object> map = apiResult.getMap();
String className = (String)map.get("className");
String methodName = (String)map.get("methodName");
Object param = map.get("param");
Object obj = null;
try {
Class clazz = Class.forName(className);
//Method method = clazz.getMethod(methodName);
Method[] methods = clazz.getMethods();
Method method = Arrays.stream(methods).filter(m->m.getName().equals(methodName)).findAny().get();
Object o = clazz.getConstructors()[0].newInstance();
obj = method.invoke(o, param);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
apiResult.setObject(obj);
return apiResult;
}
}
### 测试类
public class ProviderMain {
public static void main(String[] args) {
//spring框架
ClassPathXmlApplicationContext context=new
ClassPathXmlApplicationContext("classpath:applicationContext-provider.xml");
System.out.println("服务启动");
context.start();
while(true)
{}
}
}
依赖和配置
1.消费者和生产者依赖一样
<!-- pom依赖-->
<dependencies>
<dependency>
<groupId>com.git</groupId>
<artifactId>dubboInterface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.8</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
2.生产者配置
<!-- xml -->
<!-- 1. 设置应用名称-->
<dubbo:application name="provider-of-cart"/>
<!-- 2.配置zookeeper地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181">
</dubbo:registry>
<!-- 3.配置服务的端口号 -->
<dubbo:protocol port="20888" name="dubbo">
</dubbo:protocol>
<!-- 4.配置实现类的类名 -->
</bean>
<bean class="com.git.soc.RpcInvokerImpl" id="rpcInvoker">
</bean>
<!-- 5.配置接口名,开放服务 -->
</dubbo:service>
<dubbo:service interface="com.git.inter.RpcInvoker" ref="rpcInvoker"></dubbo:service>
</beans>
消费者
1.xml配置
<!-- 1,应用名称 -->
<dubbo:application name="consumer-of-cart"/>
<!-- 2,zookeeper -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>
<!-- 3,配置那些接口由dubbo来执行 -->
<dubbo:reference interface="com.git.inter.RpcInvoker" id="rpcInvoker"></dubbo:reference>
2.测试
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-consumer.xml");
ApiResult api = new ApiResult(0, "msg", null);
Map<String, Object> map = new HashMap<>(); map.put("className","com.git.soc.inter.impl.UserServiceImpl");
map.put("methodName","getUserRoleByUser");
User user = new User();
user.setId(2);
user.setAge(25);
user.setName("张三");
user.setSex("男");
map.put("param",user);
api.setMap(map);
System.out.println("start consumer");
//获得代理实现类
RpcInvoker rpcInvoker = (RpcInvoker) context.getBean("rpcInvoker");
//调用服务
api = rpcInvoker.invoke(api);
//api = RpcInvokeStrategy.startInvoker(api);
System.out.println("服务消费者/客户端:"+api.toString());
}
异步和回调配置
回调接口采用Function接口
//接口
public interface RoleService {
Role checkRole2(Role role, Function<Role,Role> function);
}
//生产者
public class RoleServiceImpl implements RoleService {
@Override
public Role checkRole2(Role role, Function<Role, Role> function) {
System.out.println("function函数处理");
if(role==null) throw new RuntimeException("角色不可为空");
if(role.getName().equals("财务")){
System.out.println("角色名字应该为为管理员");
return function.apply(role);
}
return role;
}
}
xml配置
<dubbo:service interface="com.git.inter.RoleService" ref="roleSevice" connections="1" callbacks="1000" ><!-- 还可以配置异步async="true"-->
<dubbo:method name="checkRole2">
<dubbo:argument index="1" callback="true" />
<!--也可以通过指定类型的方式-->
<!--<dubbo:argument type="com.demo.CallbackListener" callback="true" />-->
</dubbo:method>
</dubbo:service>
测试
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-consumer.xml");
context.start();
CallbackService callbackService = (CallbackService) context.getBean("callbackService");
RoleService roleService = context.getBean(RoleService.class);
Role role = new Role();
role.setName("财务");
System.out.println("===================角色调用开始===================");
Role role1 = roleService.checkRole2(role, r->{
System.out.println("===================开始修正===================");
System.out.println("===================修正之前===================");
System.out.println(r);
r.setName("管理");
r.setDesc("搞管理的");
return r;
});
System.out.println("===================角色调用完毕===================");
System.out.println("===================修正之后===================");
System.out.println(role1);
}
重新描述一下思路:
1.接口invoker,从消费者发出需要调用的类和方法,生产者通过反射调用
2.这么做是有项目借鉴的,可以在中间做一些网关等
3.简单调用到此结束,下一篇将采用springboot2.2与apacheDubbo整合,这里的坑比较多
本文为作者原创,转载请注明出处
github地址