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()).