最近爲了學習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地址