rpc之阿里dubbo簡單demo

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章