From bce498885e1443964475449c5ec5a6cde7473de6 Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Wed, 22 Mar 2017 16:05:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=8E=A5=E5=8F=A3=E6=94=AF?= =?UTF-8?q?=E6=8C=81AsyncHandler=E5=AD=90=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/redkale/net/http/Rest.java | 20 ++- src/org/redkale/net/http/RestHttpServlet.java | 127 ++++++++++++++ src/org/redkale/net/sncp/Sncp.java | 3 +- .../redkale/net/sncp/SncpAsyncHandler.java | 157 +++++++++++++++--- src/org/redkale/net/sncp/SncpClient.java | 6 +- src/org/redkale/net/sncp/SncpDynServlet.java | 14 +- src/org/redkale/service/Service.java | 2 +- .../redkale/test/service/ABMainService.java | 29 ++++ test/org/redkale/test/service/BCService.java | 10 ++ test/org/redkale/test/service/CService.java | 6 + .../redkale/test/service/MyAsyncHandler.java | 20 +++ 11 files changed, 362 insertions(+), 32 deletions(-) create mode 100644 test/org/redkale/test/service/MyAsyncHandler.java diff --git a/src/org/redkale/net/http/Rest.java b/src/org/redkale/net/http/Rest.java index 6d5acc738..09b28eee9 100644 --- a/src/org/redkale/net/http/Rest.java +++ b/src/org/redkale/net/http/Rest.java @@ -404,11 +404,21 @@ public final class Rest { paramMap.put("name", pname); paramMap.put("type", ptype.getName()); - if (ptype == AsyncHandler.class) { //HttpResponse.createAsyncHandler() - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Lorg/redkale/util/AsyncHandler;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[]{ALOAD, maxLocals}); + if (AsyncHandler.class.isAssignableFrom(ptype)) { //HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class) + if (ptype == AsyncHandler.class) { + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Lorg/redkale/util/AsyncHandler;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "createAsyncHandler", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/Class;)Lorg/redkale/util/AsyncHandler;", false); + mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[]{ALOAD, maxLocals}); + } hasAsyncHandler = true; } else if (annsid != null) { //HttpRequest.getSessionid(true|false) mv.visitVarInsn(ALOAD, 1); diff --git a/src/org/redkale/net/http/RestHttpServlet.java b/src/org/redkale/net/http/RestHttpServlet.java index e951d4b8c..ede7dee1b 100644 --- a/src/org/redkale/net/http/RestHttpServlet.java +++ b/src/org/redkale/net/http/RestHttpServlet.java @@ -6,6 +6,11 @@ package org.redkale.net.http; import java.io.*; +import java.util.concurrent.ConcurrentHashMap; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import org.redkale.net.sncp.SncpAsyncHandler; +import org.redkale.util.*; /** * @@ -36,4 +41,126 @@ public abstract class RestHttpServlet extends HttpBaseServlet { } } + /** + * 创建AsyncHandler实例,将非字符串对象以JSON格式输出,字符串以文本输出
+ * + * 传入的AsyncHandler子类必须是public,且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。 + * + * @param AsyncHandler泛型 + * @param response HttpResponse + * @param handlerClass Class + * + * @return AsyncHandler + */ + protected final H createAsyncHandler(HttpResponse response, final Class handlerClass) { + if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) response.createAsyncHandler(); + Creator creator = creators.get(handlerClass); + if (creator == null) { + creator = createCreator(handlerClass); + creators.put(handlerClass, creator); + } + return (H) creator.create(response.createAsyncHandler()); + } + + private static final ConcurrentHashMap creators = new ConcurrentHashMap<>(); + + private static Creator createCreator(Class handlerClass) { + //------------------------------------------------------------- + final boolean handlerinterface = handlerClass.isInterface(); + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String handlerName = AsyncHandler.class.getName().replace('.', '/'); + final String handlerDesc = Type.getDescriptor(AsyncHandler.class); + final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000); + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + AsmMethodVisitor mv; + AnnotationVisitor av0; + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName}); + + { //handler 属性 + fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null); + fv.visitEnd(); + } + {//构造方法 + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + handlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "handler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (java.lang.reflect.Method method : handlerClass.getMethods()) { // + if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newHandlerClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + return (Creator) Creator.create(newHandlerClazz); + } } diff --git a/src/org/redkale/net/sncp/Sncp.java b/src/org/redkale/net/sncp/Sncp.java index 9b705b16a..e66924292 100644 --- a/src/org/redkale/net/sncp/Sncp.java +++ b/src/org/redkale/net/sncp/Sncp.java @@ -149,7 +149,8 @@ public abstract class Sncp { } } } - if (constructorflag) throw new RuntimeException(param + " must have a empty parameter Constructor"); + if (param.getDeclaredConstructors().length == 0) constructorflag = true; + if (!constructorflag) throw new RuntimeException(param + " must have a empty parameter Constructor"); for (Method m : param.getMethods()) { if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) { throw new RuntimeException(param + "'s completed method cannot final modifier"); diff --git a/src/org/redkale/net/sncp/SncpAsyncHandler.java b/src/org/redkale/net/sncp/SncpAsyncHandler.java index 10eb80711..a549ecf27 100644 --- a/src/org/redkale/net/sncp/SncpAsyncHandler.java +++ b/src/org/redkale/net/sncp/SncpAsyncHandler.java @@ -6,9 +6,11 @@ package org.redkale.net.sncp; import java.util.logging.Level; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; import org.redkale.convert.bson.*; import org.redkale.net.sncp.SncpDynServlet.SncpServletAction; -import org.redkale.util.AsyncHandler; +import org.redkale.util.*; /** * 异步回调函数
@@ -33,59 +35,168 @@ public interface SncpAsyncHandler extends AsyncHandler { /** *
-         * 若参数类型为AsyncHandler子类,必须保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
+         *
          * 考虑点:
          *      1、AsyncHandler子类是接口,且还有其他多个方法
          *      2、AsyncHandler子类是类, 需要继承,且必须有空参数构造函数
          *      3、AsyncHandler子类无论是接口还是类,都可能存在其他泛型
          *
-         *  public class _DyncSncpAsyncHandler_xxx extends XXXAsyncHandler implements SncpAsyncHandler {
+         *  public class XXXAsyncHandler_DyncSncpAsyncHandler_4323 extends XXXAsyncHandler implements SncpAsyncHandler {
          *
-         *      public SncpAsyncHandler handler;
+         *      private SncpAsyncHandler sncphandler;
          *
-         *      protected Object[] params;
+         *      @java.beans.ConstructorProperties({"sncphandler"})
+         *      public XXXAsyncHandler_DyncSncpAsyncHandler_4323(SncpAsyncHandler sncphandler) {
+         *          super();
+         *          this.sncphandler = sncphandler;
+         *      }
          *
          *      @Override
          *      public void completed(Object result, Object attachment) {
-         *          handler.completed(result, attachment);
+         *          sncphandler.completed(result, attachment);
          *      }
          *
          *      @Override
          *      public void failed(Throwable exc, Object attachment) {
-         *          handler.failed(exc, attachment);
+         *          sncphandler.failed(exc, attachment);
          *      }
          *
          *      @Override
          *      public Object[] sncp_getParams() {
-         *          return params;
+         *          return sncphandler.sncp_getParams();
          *      }
          *
          *      @Override
          *      public void sncp_setParams(Object... params) {
-         *          this.params = params;
-         *          handler.sncp_setParams(params);
+         *          sncphandler.sncp_setParams(params);
          *      }
          *  }
          *
          * 
* - * @param 结果对象的泛型 - * @param 附件对象的泛型 * @param handlerClass AsyncHandler类型或子类 - * @param action SncpServletAction - * @param in BsonReader - * @param out BsonWriter - * @param request SncpRequest - * @param response SncpResponse * - * @return SncpAsyncHandler + * @return Creator */ - public static SncpAsyncHandler create(Class handlerClass, SncpServletAction action, - BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) { - if (handlerClass == AsyncHandler.class) return new DefaultSncpAsyncHandler(action, in, out, request, response); - //子类, 待实现 - return new DefaultSncpAsyncHandler(action, in, out, request, response); + public static Creator createCreator(Class handlerClass) { + //------------------------------------------------------------- + final boolean handlerinterface = handlerClass.isInterface(); + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String sncyHandlerName = SncpAsyncHandler.class.getName().replace('.', '/'); + final String sncyHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class); + final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + SncpAsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000); + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + AsmMethodVisitor mv; + AnnotationVisitor av0; + cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncyHandlerName} : new String[]{sncyHandlerName}); + + { //handler 属性 + fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncyHandlerDesc, null, null); + fv.visitEnd(); + } + {//构造方法 + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + sncyHandlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "sncphandler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncyHandlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (java.lang.reflect.Method method : handlerClass.getMethods()) { // + if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncyHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncyHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncyHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncyHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + { // sncp_getParams + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncyHandlerDesc); + mv.visitMethodInsn(INVOKEINTERFACE, sncyHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // sncp_setParams + mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncyHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, sncyHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newHandlerClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + return Creator.create(newHandlerClazz); } + } static class DefaultSncpAsyncHandler implements SncpAsyncHandler { diff --git a/src/org/redkale/net/sncp/SncpClient.java b/src/org/redkale/net/sncp/SncpClient.java index f7aaa808e..3a917c3c1 100644 --- a/src/org/redkale/net/sncp/SncpClient.java +++ b/src/org/redkale/net/sncp/SncpClient.java @@ -41,6 +41,8 @@ public final class SncpClient { protected final Type[] paramTypes; + protected final Class[] paramClass; + protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理,index=0固定为null, 其他为参数标记的RpcCall回调方法 protected final int handlerFuncParamIndex; @@ -60,6 +62,7 @@ public final class SncpClient { } this.resultTypes = rt == void.class ? null : rt; this.paramTypes = method.getGenericParameterTypes(); + this.paramClass = method.getParameterTypes(); this.method = method; Annotation[][] anns = method.getParameterAnnotations(); int targetAddrIndex = -1; @@ -328,11 +331,12 @@ public final class SncpClient { private SncpFuture remoteSncp0(final AsyncHandler handler, final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { Type[] myparamtypes = action.paramTypes; + Class[] myparamclass = action.paramClass; if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress; final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入 writer.writeTo(DEFAULT_HEADER); for (int i = 0; i < params.length; i++) { - bsonConvert.convertTo(writer, myparamtypes[i], params[i]); + bsonConvert.convertTo(writer, AsyncHandler.class.isAssignableFrom(myparamclass[i]) ? AsyncHandler.class : myparamtypes[i], params[i]); } final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度 final long seqid = System.nanoTime(); diff --git a/src/org/redkale/net/sncp/SncpDynServlet.java b/src/org/redkale/net/sncp/SncpDynServlet.java index 79e64a315..b55ed98ff 100644 --- a/src/org/redkale/net/sncp/SncpDynServlet.java +++ b/src/org/redkale/net/sncp/SncpDynServlet.java @@ -19,6 +19,7 @@ import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static jdk.internal.org.objectweb.asm.Opcodes.*; import jdk.internal.org.objectweb.asm.Type; import org.redkale.convert.bson.*; +import org.redkale.net.sncp.SncpAsyncHandler.DefaultSncpAsyncHandler; import org.redkale.service.*; import org.redkale.util.*; import org.redkale.service.RpcCall; @@ -123,7 +124,16 @@ public final class SncpDynServlet extends SncpServlet { SncpAsyncHandler handler = null; try { if (action.handlerFuncParamIndex >= 0) { - handler = SncpAsyncHandler.Factory.create(action.handlerFuncParamClass, action, in, out, request, response); + if (action.handlerFuncParamClass == AsyncHandler.class) { + handler = new DefaultSncpAsyncHandler(action, in, out, request, response); + } else { + Creator creator = action.handlerCreator; + if (creator == null) { + creator = SncpAsyncHandler.Factory.createCreator(action.handlerFuncParamClass); + action.handlerCreator = creator; + } + handler = creator.create(new DefaultSncpAsyncHandler(action, in, out, request, response)); + } } in.setBytes(request.getBody()); action.action(in, out, handler); @@ -143,6 +153,8 @@ public final class SncpDynServlet extends SncpServlet { public Method method; + public Creator handlerCreator; + @Resource protected BsonConvert convert; diff --git a/src/org/redkale/service/Service.java b/src/org/redkale/service/Service.java index 831a1bc8a..30551908e 100644 --- a/src/org/redkale/service/Service.java +++ b/src/org/redkale/service/Service.java @@ -22,7 +22,7 @@ import org.redkale.util.*; *
  * 异步方法:
  * Service编写异步方法:
- *    1、异步方法有且仅有一个类型为AsyncHandler的参数。
+ *    1、异步方法有且仅有一个类型为AsyncHandler的参数。若参数类型为AsyncHandler子类,必须保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
  *    2、异步方法返回类型必须是void。
  * 例如:
  *      public void insertRecord(AsyncHandler<Integer, Record> handler, String name, @RpcAttachment Record record);
diff --git a/test/org/redkale/test/service/ABMainService.java b/test/org/redkale/test/service/ABMainService.java
index a00b3e860..a4b494cf8 100644
--- a/test/org/redkale/test/service/ABMainService.java
+++ b/test/org/redkale/test/service/ABMainService.java
@@ -85,6 +85,10 @@ public class ABMainService implements Service {
         url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生";
         System.out.println(Utility.postHttpContent(url));
 
+        //异步方法
+        url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生";
+        System.out.println(Utility.postHttpContent(url));
+        
         server.shutdown();
     }
 
@@ -120,6 +124,10 @@ public class ABMainService implements Service {
         url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生";
         System.out.println(Utility.postHttpContent(url));
 
+        //异步方法
+        url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生";
+        System.out.println(Utility.postHttpContent(url));
+
         server.shutdown();
         //远程模式
         remotemain(args);
@@ -162,4 +170,25 @@ public class ABMainService implements Service {
             if (handler != null) handler.failed(t, a);
         }), name);
     }
+
+    @RestMapping(name = "asyncabtime2")
+    public void abCurrentTime(final MyAsyncHandler handler, @RestParam(name = "#") final String name) {
+        bcService.bcCurrentTime(new MyAsyncHandler() {
+            @Override
+            public int id() {
+                return 1;
+            }
+
+            @Override
+            public void completed(String v, Void a) {
+                System.out.println("执行了 ABMainService.abCurrentTime----异步方法2");
+                String rs = "异步abCurrentTime: " + v;
+                if (handler != null) handler.completed(rs, a);
+            }
+
+            @Override
+            public void failed(Throwable exc, Void attachment) {
+            }
+        }, name);
+    }
 }
diff --git a/test/org/redkale/test/service/BCService.java b/test/org/redkale/test/service/BCService.java
index 046109369..5bf42db42 100644
--- a/test/org/redkale/test/service/BCService.java
+++ b/test/org/redkale/test/service/BCService.java
@@ -33,4 +33,14 @@ public class BCService implements Service {
             if (handler != null) handler.failed(t, a);
         }), name);
     }
+    
+    public void bcCurrentTime(final MyAsyncHandler handler, final String name) {
+        cService.ccCurrentTime(AsyncHandler.create((v, a) -> {
+            System.out.println("执行了 BCService.bcCurrentTime----异步方法2");
+            String rs = "异步bcCurrentTime: " + (v == null ? null : v.getResult());
+            if (handler != null) handler.completed(rs, null);
+        }, (t, a) -> {
+            if (handler != null) handler.failed(t, a);
+        }), name);
+    }
 }
diff --git a/test/org/redkale/test/service/CService.java b/test/org/redkale/test/service/CService.java
index 70818d8df..44b06b068 100644
--- a/test/org/redkale/test/service/CService.java
+++ b/test/org/redkale/test/service/CService.java
@@ -25,4 +25,10 @@ public class CService implements Service {
         System.out.println("执行了 CService.ccCurrentTime----异步方法");
         if (handler != null) handler.completed(new RetResult(rs), null);
     }
+    
+    public void mcCurrentTime(final MyAsyncHandler, Void> handler, final String name) {
+        String rs = "异步mcCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis());
+        System.out.println("执行了 CService.mcCurrentTime----异步方法2");
+        if (handler != null) handler.completed(new RetResult(rs), null);
+    }
 }
diff --git a/test/org/redkale/test/service/MyAsyncHandler.java b/test/org/redkale/test/service/MyAsyncHandler.java
new file mode 100644
index 000000000..302c6eb86
--- /dev/null
+++ b/test/org/redkale/test/service/MyAsyncHandler.java
@@ -0,0 +1,20 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.redkale.test.service;
+
+import org.redkale.util.AsyncHandler;
+
+/**
+ *
+ * @author zhangjx
+ * @param  V
+ * @param  A
+ */
+public abstract class MyAsyncHandler implements AsyncHandler {
+
+    public abstract int id();
+
+}