异步接口支持AsyncHandler子类

This commit is contained in:
Redkale
2017-03-22 16:05:10 +08:00
parent eb57a25698
commit bce498885e
11 changed files with 362 additions and 32 deletions

View File

@@ -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);

View File

@@ -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<T> extends HttpBaseServlet {
}
}
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出 <br>
*
* 传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
*
* @param <H> AsyncHandler泛型
* @param response HttpResponse
* @param handlerClass Class
*
* @return AsyncHandler
*/
protected final <H extends AsyncHandler> H createAsyncHandler(HttpResponse response, final Class<H> handlerClass) {
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) response.createAsyncHandler();
Creator<H> creator = creators.get(handlerClass);
if (creator == null) {
creator = createCreator(handlerClass);
creators.put(handlerClass, creator);
}
return (H) creator.create(response.createAsyncHandler());
}
private static final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap<>();
private static <H extends AsyncHandler> Creator<H> createCreator(Class<H> 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, "<init>", "(" + 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, "<init>", "()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<SncpAsyncHandler> newHandlerClazz = (Class<SncpAsyncHandler>) 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<H>) Creator.create(newHandlerClazz);
}
}

View File

@@ -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");

View File

@@ -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.*;
/**
* 异步回调函数 <br>
@@ -33,59 +35,168 @@ public interface SncpAsyncHandler<V, A> extends AsyncHandler<V, A> {
/**
* <blockquote><pre>
* 若参数类型为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;
* &#64;java.beans.ConstructorProperties({"sncphandler"})
* public XXXAsyncHandler_DyncSncpAsyncHandler_4323(SncpAsyncHandler sncphandler) {
* super();
* this.sncphandler = sncphandler;
* }
*
* &#64;Override
* public void completed(Object result, Object attachment) {
* handler.completed(result, attachment);
* sncphandler.completed(result, attachment);
* }
*
* &#64;Override
* public void failed(Throwable exc, Object attachment) {
* handler.failed(exc, attachment);
* sncphandler.failed(exc, attachment);
* }
*
* &#64;Override
* public Object[] sncp_getParams() {
* return params;
* return sncphandler.sncp_getParams();
* }
*
* &#64;Override
* public void sncp_setParams(Object... params) {
* this.params = params;
* handler.sncp_setParams(params);
* sncphandler.sncp_setParams(params);
* }
* }
*
* </pre></blockquote>
*
* @param <V> 结果对象的泛型
* @param <A> 附件对象的泛型
* @param handlerClass AsyncHandler类型或子类
* @param action SncpServletAction
* @param in BsonReader
* @param out BsonWriter
* @param request SncpRequest
* @param response SncpResponse
*
* @return SncpAsyncHandler
* @return Creator
*/
public static <V, A> SncpAsyncHandler<V, A> create(Class<? extends AsyncHandler> 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<SncpAsyncHandler> createCreator(Class<? extends AsyncHandler> 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, "<init>", "(" + 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, "<init>", "()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<SncpAsyncHandler> newHandlerClazz = (Class<SncpAsyncHandler>) 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<V, A> implements SncpAsyncHandler<V, A> {

View File

@@ -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<byte[]> 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();

View File

@@ -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<SncpAsyncHandler> 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<SncpAsyncHandler> handlerCreator;
@Resource
protected BsonConvert convert;

View File

@@ -22,7 +22,7 @@ import org.redkale.util.*;
* <blockquote><pre>
* 异步方法:
* Service编写异步方法
* 1、异步方法有且仅有一个类型为AsyncHandler的参数。
* 1、异步方法有且仅有一个类型为AsyncHandler的参数。若参数类型为AsyncHandler子类必须保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
* 2、异步方法返回类型必须是void。
* 例如:
* public void insertRecord(AsyncHandler&#60;Integer, Record&#62; handler, String name, &#64;RpcAttachment Record record);

View File

@@ -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<String, Void> handler, @RestParam(name = "#") final String name) {
bcService.bcCurrentTime(new MyAsyncHandler<String, Void>() {
@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);
}
}

View File

@@ -33,4 +33,14 @@ public class BCService implements Service {
if (handler != null) handler.failed(t, a);
}), name);
}
public void bcCurrentTime(final MyAsyncHandler<String, Void> 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);
}
}

View File

@@ -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<RetResult<String>, 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);
}
}

View File

@@ -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> V
* @param <A> A
*/
public abstract class MyAsyncHandler<V, A> implements AsyncHandler<V, A> {
public abstract int id();
}