使用Java8的函数式接口@FunctionalInterface实现简单异步调用

  最近研究了一下异步调用,接下来几篇博客是跟异步调用相关的,首先使用@FunctionalInterface接口实现一个简单的步调用,也就是本篇博客主要内容。

然后再加上ZMQ,实现一个带网络通信的异步调用。再下一步就是复杂一点的RPC调用,最终目的是实现一个使用ZMQ的分布式调用系统。

  Flag已经立,目标也定好了,先从简单的说起。

  情景假设:假设一个程序需求是用户Person查看用户密码,这个需要访问数据库,可能是耗时操作,把这个做成异步调用。

1  @FunctionalInterface介绍:

    FunctionalInterface的接口被称为函数式接口,该接口只能有一个自定义方法,但是可以包括从object类继承而来的方法。如果一个接口只有一个方  法,则编译器会认为这就是一个函数式接口

   定义一个@FunctionalInterface接口:

  1. package com.zjq.java8.methodInterface;  
  2.   
  3. @FunctionalInterface  
  4. public interface GofFunction<T1,T2> {  
  5.     public void execute(T1 t1,T2 t2);  
  6. }  
2 定义一个参数包装类,可以包装任何参数:

 

  1. package com.zjq.java8.methodInterface;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. public class ParamContext {  
  7.     private Map<String,Object> datas=new HashMap<String,Object>();  
  8.     public ParamContext(Object...params){  
  9.         if(params==null||params.length==0){  
  10.             return;  
  11.         }  
  12.         for(int i=0;i<params.length;){  
  13.             datas.put((String) params[i], params[i+1]);  
  14.             i+=2;  
  15.         }  
  16.     }  
  17.     @SuppressWarnings("unchecked")  
  18.     public <R> R get(String key){  
  19.         return (R)datas.get(key);  
  20.     }  
  21. }  
3 定义一个监听类,里面有两个map,一个是所调用方法的map,一个是对应参数的map,map的key值是生成的uuid

  1. package com.zjq.java8.methodInterface;  
  2.   
  3. import java.util.UUID;  
  4. import java.util.concurrent.ConcurrentHashMap;  
  5.   
  6. public class ListenCall {  
  7.     ConcurrentHashMap<String,GofFunction<ParamContext, ParamContext>> methodMap=new ConcurrentHashMap<String,GofFunction<ParamContext, ParamContext>>();  
  8.     ConcurrentHashMap<String,ParamContext> paramMap=new ConcurrentHashMap<String,ParamContext>();  
  9.   
  10.     /** 
  11.      * 获取请求编号 
  12.      * @return 
  13.      */  
  14.     public  String getCallId(){  
  15.         UUID uuid = UUID.randomUUID();  
  16.         return uuid.toString();  
  17.     }  
  18.     /** 
  19.      * 监听返回值 
  20.      * @param method 
  21.      * @param callId 
  22.      * @param context 
  23.      */  
  24.     public void listenResult(GofFunction<ParamContext, ParamContext> method,String callId,ParamContext context) {  
  25.         methodMap.put(callId, method);  
  26.         paramMap.put(callId, context);  
  27.     }  
  28.     /** 
  29.      * 等待处理结果 
  30.      * @param result 
  31.      * @param callId 
  32.      */  
  33.     public  void waitForResult(ParamContext result,String callId){  
  34.         GofFunction<ParamContext, ParamContext> funtion=methodMap.get(callId);  
  35.         if(funtion!=null){  
  36.             ParamContext context=paramMap.get(callId);  
  37.             if(context==null){  
  38.                 context=new ParamContext();  
  39.             }  
  40.                 funtion.execute(result,context);  
  41.         }  
  42.           
  43.     }  
  44.   
  45. }  
4 定义person的service类,里面有一些逻辑方法,有一个模拟读取数据库的方法,此方法是多线程的,模拟读取数据库,线程休眠4秒。

  1. package com.zjq.java8.methodInterface;  
  2.   
  3. public class PersonService {  
  4.     private ListenCall listenCall=new ListenCall();  
  5.       
  6.       
  7.     /** 
  8.      * 这里模拟根据用户名从数据库查询密码 
  9.      * @param name 用户名 
  10.      * @param callId 请求调用的id 
  11.      */  
  12.     public void getPwdFromDb(String name,String callId){  
  13.         new  Thread(new Runnable() {  
  14.               
  15.             @Override  
  16.             public void run() {  
  17.                 String sql="select from person where name="+"'"+name+"'";  
  18.                 String pwd="1111";  
  19.                 try {  
  20.                     //这里等待4秒,模拟毒区数据库的书剑,时间有点夸张  
  21.                     Thread.sleep(4000);  
  22.                 } catch (InterruptedException e) {  
  23.                     e.printStackTrace();  
  24.                 }  
  25.                 waitForResult(new ParamContext("pwd",pwd),callId);  
  26.             }  
  27.         }).start();  
  28.     }  
  29.     public String getCallId(){  
  30.         return listenCall.getCallId();  
  31.     }  
  32.     public void waitForResult(ParamContext p,String callId){  
  33.         listenCall.waitForResult(p, callId);  
  34.     }  
  35.     public void listenResult(GofFunction<ParamContext, ParamContext> method,String callId,ParamContext context){  
  36.         listenCall.listenResult(method, callId, context);  
  37.     }  
  38. }  
5 用户的管理类。

 

  1. package com.zjq.java8.methodInterface;  
  2.   
  3. public class PersonManager {  
  4.     PersonService personService=new PersonService();  
  5.   
  6.   
  7.     public static void main(String[] args) {  
  8.         PersonManager callTest=new PersonManager();  
  9.         callTest.seePwd();  
  10.   
  11.     }  
  12.     /** 
  13.      * 假设用户想查看一下密码 
  14.      */  
  15.     private void seePwd(){  
  16.         String name="1111";  
  17.         String time=String.valueOf(System.currentTimeMillis());  
  18.         String callId=personService.getCallId();  
  19.         personService.getPwdFromDb(name,callId);  
  20.         personService.listenResult(this::getPwd,callId,new ParamContext("time",time));  
  21.         System.out.println("数据库读取数据,可能有点耗时,这里做成异步操作,我先做其他事情。。。。。。。。。");  
  22.     }  
  23.       
  24.     /** 
  25.      * 获取到了密码 
  26.      * @param result 
  27.      * @param context 
  28.      */  
  29.     private void getPwd(ParamContext result,ParamContext context){  
  30.         String pwd=result.get("pwd");  
  31.         long sed=(System.currentTimeMillis()-Long.valueOf(context.get("time")))/1000;  
  32.         System.out.println("经过"+sed+"秒"+"查询用户密码的调用终于返回了");  
  33.         System.out.println("得到密码:"+pwd);      
  34.     }  
  35. }  
6 程序执行结果:

  1. 数据库读取数据,可能有点耗时,这里做成异步操作,我先做其他事情。。。。。。。。。  
  2. 经过4秒查询用户密码的调用终于返回了  
  3. 得到密码:1111  
分析,程序先打印的第一句,等4秒后才打印后面的,说明异步调用成功。

猜你喜欢

转载自blog.csdn.net/ztx114/article/details/79206096
今日推荐