Expensive calls to getDeclaredMethods while creating joinpoi
jaikiran May 5, 2009 12:22 PMWhile working on performance improvement of EJB3 deployments (EJBTHREE-1800), i have been seeing that most of the time is spent in AOP (ex: finding annotations, creating interceptor chains etc...).
The sample app that i am trying is 100 EJBs with 100 methods each. (The performance degrades drastically as the number of methods increases)
One of the issues relates to the way a joinpoint for a method is created
Here's the flow:
- (AOP) Interceptor chain for EJB containers is created
- While the chain is being created, the corresponding AspectFactory are created
protected Object createBean(ClassLoader cl) throws Throwable
{
ClassLoader loader = cl;
if (loader == null)
loader = Configurator.getClassLoader(classLoader);
BeanInfo info = null;
if (bean != null)
info = configurator.getBeanInfo(bean, loader, accessMode);
Joinpoint joinpoint = configurator.getConstructorJoinPoint(info, constructor, null);
....//blah blah blah
invokeLifecycle("create", create, info, loader, result);
invokeLifecycle("start", start, info, loader, result);
return result;
}
The invokeLifecycle tries to call the create() and start() methods if any:
protected void invokeLifecycle(String methodName, LifecycleMetaData lifecycle, BeanInfo info, ClassLoader cl, Object target) throws Throwable
{
if (lifecycle == null || lifecycle.isIgnored() == false)
{
String method = methodName;
if (lifecycle != null && lifecycle.getMethodName() != null)
method = lifecycle.getMethodName();
List<ParameterMetaData> parameters = null;
if (lifecycle != null)
parameters = lifecycle.getParameters();
MethodJoinpoint joinpoint;
try
{
joinpoint = configurator.getMethodJoinPoint(info, cl, method, parameters, false, true);
}
...// blah blah
The calls goes to AbstractKernelConfigurator.getMethodJoinPoint:
public MethodJoinpoint getMethodJoinPoint(BeanInfo info, ClassLoader cl, String name, List<ParameterMetaData> parameters, boolean isStatic, boolean isPublic) throws Throwable
{
return Configurator.findMethod(info, cl, name, parameters, isStatic, isPublic);
}
The findMethod ultimately leads to this implementation in org.jboss.joinpoint.plugins.Config
public static MethodInfo findMethodInfo(ClassInfo classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) throws JoinpointException
{
...// blah blah
MethodInfo result = locateMethodInfo(current, name, paramTypes, isStatic, isPublic, strict);
if (result != null)
return result;
current = current.getSuperclass();
}
The implementation for locateMethodInfo looks unnecessarily expensive:
private static MethodInfo locateMethodInfo(ClassInfo classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict)
{
MethodInfo[] methods = classInfo.getDeclaredMethods();
if (methods != null)
{
for (int i = 0; i < methods.length; ++i)
{
if (name.equals(methods[ i].getName()) &&
equals(paramTypes, methods[ i].getParameterTypes()) &&
(strict == false || (methods[ i].isStatic() == isStatic && methods[ i].isPublic() == isPublic)))
return methods[ i];
}
}
return null;
}
This locateMethodInfo is passed with the method name and params, so any specific reason why it needs to get all the declared methods and then do a equals on them instead of using the other API on ClassInfo which accepts the method name and params:
MethodInfo getDeclaredMethod(String name, TypeInfo[] parameters);
The current implementation leads to a performance degradation when the number of methods increases (All this piece of code is trying to do is find a couple of methods named create() and start()).