Changed reflection to use (much faster) ReflectASM

This commit is contained in:
nathan 2015-02-08 14:51:30 +01:00
parent 2e7cc11799
commit 220e522ff0
6 changed files with 119 additions and 152 deletions

View File

@ -1,6 +1,6 @@
package net.engio.mbassy.dispatch;
import java.lang.reflect.Method;
import com.esotericsoftware.reflectasm.MethodAccess;
/**
* A handler invocation encapsulates the logic that is used to invoke a single
@ -28,7 +28,7 @@ public interface IHandlerInvocation {
* type that the handler consumes
* @param handler The handler (method) that will be called via reflection
*/
void invoke(Object listener, Method handler, Object message) throws Throwable;
void invoke(Object listener, MethodAccess handler, int methodIndex, Object message) throws Throwable;
/**
* Invoke the message delivery logic of this handler
@ -39,7 +39,7 @@ public interface IHandlerInvocation {
* type that the handler consumes
* @param handler The handler (method) that will be called via reflection
*/
void invoke(Object listener, Method handler, Object message1, Object message2) throws Throwable;
void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2) throws Throwable;
/**
* Invoke the message delivery logic of this handler
@ -50,7 +50,7 @@ public interface IHandlerInvocation {
* type that the handler consumes
* @param handler The handler (method) that will be called via reflection
*/
void invoke(Object listener, Method handler, Object message1, Object message2, Object message3) throws Throwable;
void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2, Object message3) throws Throwable;
/**
* Invoke the message delivery logic of this handler
@ -61,5 +61,5 @@ public interface IHandlerInvocation {
* type that the handler consumes
* @param handler The handler (method) that will be called via reflection
*/
void invoke(Object listener, Method handler, Object... message) throws Throwable;
void invoke(Object listener, MethodAccess handler, int methodIndex, Object... message) throws Throwable;
}

View File

@ -1,6 +1,6 @@
package net.engio.mbassy.dispatch;
import java.lang.reflect.Method;
import com.esotericsoftware.reflectasm.MethodAccess;
/**
* Uses reflection to invoke a message handler for a given message.
@ -17,22 +17,22 @@ public class ReflectiveHandlerInvocation implements IHandlerInvocation {
}
@Override
public void invoke(final Object listener, Method handler, final Object message) throws Throwable {
handler.invoke(listener, message);
public void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable {
handler.invoke(listener, methodIndex, message);
}
@Override
public void invoke(final Object listener, Method handler, final Object message1, final Object message2) throws Throwable {
handler.invoke(listener, message1, message2);
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2) throws Throwable {
handler.invoke(listener, methodIndex, message1, message2);
}
@Override
public void invoke(final Object listener, Method handler, final Object message1, final Object message2, final Object message3) throws Throwable {
handler.invoke(listener, message1, message2, message3);
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable {
handler.invoke(listener, methodIndex, message1, message2, message3);
}
@Override
public void invoke(final Object listener, Method handler, final Object... messages) throws Throwable {
handler.invoke(listener, messages);
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object... messages) throws Throwable {
handler.invoke(listener, methodIndex, messages);
}
}

View File

@ -1,6 +1,6 @@
package net.engio.mbassy.dispatch;
import java.lang.reflect.Method;
import com.esotericsoftware.reflectasm.MethodAccess;
/**
* Synchronizes message handler invocations for all handlers that specify @Synchronized
@ -19,30 +19,30 @@ public class SynchronizedHandlerInvocation implements IHandlerInvocation {
}
@Override
public void invoke(final Object listener, Method handler, final Object message) throws Throwable {
public void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable {
synchronized (listener) {
this.delegate.invoke(listener, handler, message);
this.delegate.invoke(listener, handler, methodIndex, message);
}
}
@Override
public void invoke(final Object listener, Method handler, final Object message1, final Object message2) throws Throwable {
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2) throws Throwable {
synchronized (listener) {
this.delegate.invoke(listener, handler, message1, message2);
this.delegate.invoke(listener, handler, methodIndex, message1, message2);
}
}
@Override
public void invoke(final Object listener, Method handler, final Object message1, final Object message2, final Object message3) throws Throwable {
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable {
synchronized (listener) {
this.delegate.invoke(listener, handler, message1, message2, message3);
this.delegate.invoke(listener, handler, methodIndex, message1, message2, message3);
}
}
@Override
public void invoke(final Object listener, Method handler, final Object... messages) throws Throwable {
public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object... messages) throws Throwable {
synchronized (listener) {
this.delegate.invoke(listener, handler, messages);
this.delegate.invoke(listener, handler, methodIndex, messages);
}
}
}

View File

@ -1,6 +1,5 @@
package net.engio.mbassy.error;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
@ -20,7 +19,7 @@ public class PublicationError {
// Internal state
private Throwable cause;
private String message;
private Method handler;
private String methodName;
private Object listener;
private Object[] publishedObjects;
@ -59,12 +58,12 @@ public class PublicationError {
return this;
}
public Method getHandler() {
return this.handler;
public String getMethodName() {
return this.methodName;
}
public PublicationError setHandler(Method handler) {
this.handler = handler;
public PublicationError setMethodName(String methodName) {
this.methodName = methodName;
return this;
}
@ -122,7 +121,7 @@ public class PublicationError {
newLine +
"\tmessage='" + this.message + '\'' +
newLine +
"\thandler=" + this.handler +
"\tmethod=" + this.methodName +
newLine +
"\tlistener=" + this.listener +
newLine +

View File

@ -1,6 +1,5 @@
package net.engio.mbassy.listener;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -8,6 +7,8 @@ import net.engio.mbassy.annotations.Handler;
import net.engio.mbassy.annotations.Synchronized;
import net.engio.mbassy.common.ReflectionUtils;
import com.esotericsoftware.reflectasm.MethodAccess;
/**
* Any method in any class annotated with the @Handler annotation represents a message handler. The class that contains
* the handler is called a message listener and more generally, any class containing a message handler in its class hierarchy
@ -29,7 +30,8 @@ import net.engio.mbassy.common.ReflectionUtils;
*/
public class MessageHandler {
private final Method handler;
private final MethodAccess handler;
private final int methodIndex;
private final Class<?>[] handledMessages;
private final boolean acceptsSubtypes;
private final MessageListener listenerConfig;
@ -46,9 +48,10 @@ public class MessageHandler {
}
Class<?>[] handledMessages = handler.getParameterTypes();
handler.setAccessible(true);
this.handler = handler;
this.handler = MethodAccess.get(handler.getDeclaringClass());
this.methodIndex = this.handler.getIndex(handler.getName(), handledMessages);
this.acceptsSubtypes = !handlerConfig.rejectSubtypes();
this.listenerConfig = listenerMetadata;
this.isSynchronized = ReflectionUtils.getAnnotation(handler, Synchronized.class) != null;
@ -59,10 +62,6 @@ public class MessageHandler {
this.isVarArg = handledMessages.length == 1 && handledMessages[0].isArray();
}
public <A extends Annotation> A getAnnotation(Class<A> annotationType){
return ReflectionUtils.getAnnotation(this.handler,annotationType);
}
public boolean isSynchronized(){
return this.isSynchronized;
}
@ -71,10 +70,14 @@ public class MessageHandler {
return this.listenerConfig.isFromListener(listener);
}
public Method getHandler() {
public MethodAccess getHandler() {
return this.handler;
}
public int getMethodIndex() {
return this.methodIndex;
}
public Class<?>[] getHandledMessages() {
return this.handledMessages;
}

View File

@ -1,7 +1,6 @@
package net.engio.mbassy.subscription;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import net.engio.mbassy.common.IConcurrentSet;
@ -13,6 +12,8 @@ import net.engio.mbassy.error.ErrorHandlingSupport;
import net.engio.mbassy.error.PublicationError;
import net.engio.mbassy.listener.MessageHandler;
import com.esotericsoftware.reflectasm.MethodAccess;
/**
* A subscription is a thread-safe container that manages exactly one message handler of all registered
* message listeners of the same class, i.e. all subscribed instances (excluding subclasses) of a SingleMessageHandler.class
@ -126,27 +127,18 @@ public class Subscription {
public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message) {
if (this.listeners.size() > 0) {
/**
* Delivers the given message to the given set of listeners.
* Delivery may be delayed, aborted or restricted in various ways, depending
* on the configuration of the dispatcher
*
* @param publication The message publication that initiated the dispatch
* @param message The message that should be delivered to the listeners
* @param listeners The listeners that should receive the message
*/
Method handler = this.handlerMetadata.getHandler();
MethodAccess handler = this.handlerMetadata.getHandler();
int methodIndex = this.handlerMetadata.getMethodIndex();
for (Object listener : this.listeners) {
try {
this.invocation.invoke(listener, handler, message);
this.invocation.invoke(listener, handler, methodIndex, message);
} catch (IllegalAccessException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message));
} catch (IllegalArgumentException e) {
@ -155,7 +147,7 @@ public class Subscription {
"Wrong arguments passed to method. Was: " + message.getClass()
+ "Expected: " + handler.getParameterTypes()[0])
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message));
} catch (InvocationTargetException e) {
@ -163,7 +155,7 @@ public class Subscription {
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message));
} catch (Throwable e) {
@ -171,7 +163,7 @@ public class Subscription {
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message));
}
@ -181,27 +173,18 @@ public class Subscription {
public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message1, Object message2) {
if (this.listeners.size() > 0) {
/**
* Delivers the given message to the given set of listeners.
* Delivery may be delayed, aborted or restricted in various ways, depending
* on the configuration of the dispatcher
*
* @param publication The message publication that initiated the dispatch
* @param message The message that should be delivered to the listeners
* @param listeners The listeners that should receive the message
*/
Method handler = this.handlerMetadata.getHandler();
MethodAccess handler = this.handlerMetadata.getHandler();
int methodIndex = this.handlerMetadata.getMethodIndex();
for (Object listener : this.listeners) {
try {
this.invocation.invoke(listener, handler, message1, message2);
this.invocation.invoke(listener, handler, methodIndex, message1, message2);
} catch (IllegalAccessException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2));
} catch (IllegalArgumentException e) {
@ -214,7 +197,7 @@ public class Subscription {
handler.getParameterTypes()[1]
)
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2));
} catch (InvocationTargetException e) {
@ -222,7 +205,7 @@ public class Subscription {
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2));
} catch (Throwable e) {
@ -230,7 +213,7 @@ public class Subscription {
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setHandler(handler)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2));
}
@ -240,60 +223,51 @@ public class Subscription {
public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message1, Object message2, Object message3) {
if (this.listeners.size() > 0) {
/**
* Delivers the given message to the given set of listeners.
* Delivery may be delayed, aborted or restricted in various ways, depending
* on the configuration of the dispatcher
*
* @param publication The message publication that initiated the dispatch
* @param message The message that should be delivered to the listeners
* @param listeners The listeners that should receive the message
*/
Method handler = this.handlerMetadata.getHandler();
MethodAccess handler = this.handlerMetadata.getHandler();
int methodIndex = this.handlerMetadata.getMethodIndex();
for (Object listener : this.listeners) {
try {
this.invocation.invoke(listener, handler, message1, message2, message3);
this.invocation.invoke(listener, handler, methodIndex, message1, message2, message3);
} catch (IllegalAccessException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(message1, message2, message3));
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2, message3));
} catch (IllegalArgumentException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"Wrong arguments passed to method. Was: " +
message1.getClass() + ", " +
message2.getClass() + ", " +
message3.getClass()
+ ". Expected: " + handler.getParameterTypes()[0] + ", " +
handler.getParameterTypes()[1] + ", " +
handler.getParameterTypes()[2]
)
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(message1, message2, message3));
.setMessage("Error during invocation of message handler. " +
"Wrong arguments passed to method. Was: " +
message1.getClass() + ", " +
message2.getClass() + ", " +
message3.getClass()
+ ". Expected: " + handler.getParameterTypes()[0] + ", " +
handler.getParameterTypes()[1] + ", " +
handler.getParameterTypes()[2]
)
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2, message3));
} catch (InvocationTargetException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(message1, message2, message3));
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2, message3));
} catch (Throwable e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(message1, message2, message3));
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(message1, message2, message3));
}
}
}
@ -301,54 +275,45 @@ public class Subscription {
public void publishToSubscription(ErrorHandlingSupport errorHandler, Object... messages) {
if (this.listeners.size() > 0) {
/**
* Delivers the given message to the given set of listeners.
* Delivery may be delayed, aborted or restricted in various ways, depending
* on the configuration of the dispatcher
*
* @param publication The message publication that initiated the dispatch
* @param message The message that should be delivered to the listeners
* @param listeners The listeners that should receive the message
*/
Method handler = this.handlerMetadata.getHandler();
MethodAccess handler = this.handlerMetadata.getHandler();
int methodIndex = this.handlerMetadata.getMethodIndex();
for (Object listener : this.listeners) {
try {
this.invocation.invoke(listener, handler, messages);
this.invocation.invoke(listener, handler, methodIndex, messages);
} catch (IllegalAccessException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(messages));
.setMessage("Error during invocation of message handler. " +
"The class or method is not accessible")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(messages));
} catch (IllegalArgumentException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"Wrong arguments passed to method. Was: " + Arrays.deepToString(messages)
+ "Expected: " + Arrays.deepToString(handler.getParameterTypes()))
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(messages));
.setMessage("Error during invocation of message handler. " +
"Wrong arguments passed to method. Was: " + Arrays.deepToString(messages)
+ "Expected: " + Arrays.deepToString(handler.getParameterTypes()))
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(messages));
} catch (InvocationTargetException e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(messages));
.setMessage("Error during invocation of message handler. " +
"Message handler threw exception")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(messages));
} catch (Throwable e) {
errorHandler.handlePublicationError(new PublicationError()
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setHandler(handler)
.setListener(listener)
.setPublishedObject(messages));
.setMessage("Error during invocation of message handler. " +
"The handler code threw an exception")
.setCause(e)
.setMethodName(handler.getMethodNames()[methodIndex])
.setListener(listener)
.setPublishedObject(messages));
}
}
}