While working on improving the EJB3 deployment time
https://jira.jboss.org/jira/browse/EJBTHREE-1800 i noticed that MC aggresively scans for
annotations on MC beans (we deploy EJB3 containers and EJB3 proxy factories as MC beans)
and their methods and fields. MC does this to process these annotations (if present)
through various AnnotationPlugins. However, the way its currently done:
1) Get all plugins
2) Create a method/field/constructor signature from MethodInfo/FieldInfo/ConstructorInfo
3) Create ComponentMetaData for these signatures (internally leads to reflection on the
classes/methods).
4) Pass this info to the plugin which *then* checks to see whether it can process the
annotation. If it can't then step #2 and #3 go waste
These steps are repeated when the plugin is being applied (deployment) and once during
cleanup (undeployment).
Profiling the application shows that step#3 turns into a hotspot when the number of beans
increases and the number of methods and fields on the beans increases. Also the logs show
a lot of these statements :
2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ExternalInstallAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.ExternalInstalls
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.SupplysAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Supplys
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.AliasesAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Aliases
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.DemandsAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Demands
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ClassFactoryAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Factory
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.BeanAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Bean
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ExternalUninstallAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.ExternalUninstalls
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.DependsAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Depends
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ConstructorParameterAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Constructor
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.StringValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.StringValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.NullValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.NullValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ArrayValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ArrayValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ListValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ListValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.PropertyInstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Install
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ValueFactoryAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ValueFactory
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.MapValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.MapValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.InjectAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Inject
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.SetValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.SetValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.JavaBeanValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.JavaBeanValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.CollectionValueAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.CollectionValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ThisValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ThisValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.PropertyUninstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Uninstall
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.StringValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.StringValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.NullValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.NullValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ArrayValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ArrayValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ListValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ListValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.PropertyInstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Install
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.ValueFactoryAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.ValueFactory
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.MapValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.MapValue
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.InjectAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Inject
| 2009-04-03 16:50:55,256 TRACE
[org.jboss.kernel.plugins.annotations.SetValueAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.SetValue
| ...// removed a lot of similar log lines, intentionally
| ...
| ...
|
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.MethodUninstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Uninstall
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.DestroyLifecycleAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Destroy
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.UninstallMethodParameterAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.UninstallMethod
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.FactoryMethodAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.FactoryMethod
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.StopLifecycleAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.Stop
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.StartLifecycleAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Start
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.MethodInstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Install
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.CreateLifecycleAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Create
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.InstallMethodParameterAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.InstallMethod
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.MethodUninstallCallbackAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Uninstall
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.DestroyLifecycleAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.Destroy
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.UninstallMethodParameterAnnotationPlugin] (main) No
annotation: org.jboss.beans.metadata.api.annotations.UninstallMethod
| 2009-04-03 16:50:55,261 TRACE
[org.jboss.kernel.plugins.annotations.FactoryMethodAnnotationPlugin] (main) No annotation:
org.jboss.beans.metadata.api.annotations.FactoryMethod
|
From what i see in the code
(org.jboss.kernel.plugins.annotations.CommonAnnotationAdapter.java), i think there's
chance for optimization :
1) We have all the annotation plugins and hence know which annotations, they can handle
2) The MethodInfo/ConstructorInfo/FieldInfo, provides a isAnnotationPresent(...) API.
3) Use this API and compare it against *all the plugins* to filter out only relevant
plugins that can process these annotations
4) Most of the times, most of the methods/fields will have no annotations and hence those
methods will get skipped.
5) After we have a non-empty collection of plugins, we can then go on to create the
method/field signatures and the ComponentMetadata
Here's the patch which i came up with:
| Index:
src/main/java/org/jboss/kernel/plugins/annotations/CommonAnnotationAdapter.java
| ===================================================================
| ---
src/main/java/org/jboss/kernel/plugins/annotations/CommonAnnotationAdapter.java (revision
86731)
| +++
src/main/java/org/jboss/kernel/plugins/annotations/CommonAnnotationAdapter.java (working
copy)
| @@ -25,7 +25,9 @@
| import java.lang.annotation.ElementType;
| import java.lang.annotation.Retention;
| import java.lang.annotation.Target;
| +import java.util.ArrayList;
| import java.util.HashSet;
| +import java.util.List;
| import java.util.Set;
|
| import org.jboss.beans.info.spi.BeanInfo;
| @@ -209,11 +211,36 @@
| {
| for(ConstructorInfo ci : constructors)
| {
| + // let's first find only relevant plugins, through ConstructorInfo,
before
| + // creating the constructor signature and retrieving the
ComponentMetadata
| + Set<T> relevantConstructorAnnotationPlugins = new
HashSet<T>(constructorAnnotationPlugins);
| + for(T plugin : constructorAnnotationPlugins)
| + {
| + // Can this constructor be handled by the plugin?
| + if (!ci.isAnnotationPresent(plugin.getAnnotation()))
| + {
| + // if not then ignore this plugin from processing this constructor
| + if (log.isTraceEnabled())
| + {
| + log.trace("Plugin " + plugin + " with annotation
" + plugin.getAnnotation().getName() + " is not relevant for constructor "
+ ci.toString());
| + }
| + // remove this plugin from list of relevant plugins
| + relevantConstructorAnnotationPlugins.remove(plugin);
| + }
| + }
| + // if there are no plugins which can handle this constructor,
| + // then no use creating a constructor signature and processing further.
| + // Just move on to the next constructor
| + if (relevantConstructorAnnotationPlugins.isEmpty())
| + {
| + continue;
| + }
| Signature cis = new ConstructorSignature(ci);
| MetaData cmdr = retrieval.getComponentMetaData(cis);
| if (cmdr != null)
| {
| - for(T plugin : constructorAnnotationPlugins)
| + // only consider relevant plugins for this constructor
| + for(T plugin : relevantConstructorAnnotationPlugins)
| {
| if (isApplyPhase)
| applyPlugin(plugin, ci, cmdr, handle);
| @@ -238,11 +265,37 @@
| FieldInfo field = pi.getFieldInfo();
| if (field != null)
| {
| + // let's first find only relevant plugins, through FieldInfo,
before
| + // creating the field signature and retrieving the ComponentMetadata
| + Set<T> relevantFiledAnnotationPlugins = new
HashSet<T>(fieldAnnotationPlugins);
| + for(T plugin : fieldAnnotationPlugins)
| + {
| + // Can this field be handled by the plugin?
| + if (!field.isAnnotationPresent(plugin.getAnnotation()))
| + {
| + // if not then ignore this plugin from processing this field
| + if (log.isTraceEnabled())
| + {
| + log.trace("Plugin " + plugin + " with
annotation " + plugin.getAnnotation().getName() + " is not relevant for field
" + field.toString());
| + }
| + // remove this plugin from list of relevant plugins
| + relevantFiledAnnotationPlugins.remove(plugin);
| + }
| + }
| + // if there are no plugins which can handle this field,
| + // then no use creating a field signature and processing further.
| + // Just move on to the next field
| + if (relevantFiledAnnotationPlugins.isEmpty())
| + {
| + continue;
| + }
| +
| Signature sis = new FieldSignature(field);
| MetaData cmdr = retrieval.getComponentMetaData(sis);
| if (cmdr != null)
| {
| - for(T plugin : fieldAnnotationPlugins)
| + // only consider the relevant plugins for this field
| + for(T plugin : relevantFiledAnnotationPlugins)
| {
| if (isApplyPhase)
| applyPlugin(plugin, field, cmdr, handle);
| @@ -269,11 +322,37 @@
| {
| if (visitedMethods.contains(mi) == false)
| {
| + // let's first find only relevant plugins, through MethodInfo,
before
| + // creating the method signature and retrieving the ComponentMetadata
| + Set<T> relevantMethodAnnotationPlugins = new
HashSet<T>(methodAnnotationPlugins);
| + for(T plugin : methodAnnotationPlugins)
| + {
| + // Can this method be handled by the plugin?
| + if (!mi.isAnnotationPresent(plugin.getAnnotation()))
| + {
| + // if not then ignore this plugin from processing this method
| + if (log.isTraceEnabled())
| + {
| + log.trace("Plugin " + plugin + " with
annotation " + plugin.getAnnotation().getName() + " is not relevant for method
" + mi.toString());
| + }
| + // remove this plugin from list of relevant plugins
| + relevantMethodAnnotationPlugins.remove(plugin);
| + }
| + }
| + // if there are no plugins which can handle this method,
| + // then no use creating a method signature and processing further.
| + // Just move on to the next method
| + if (relevantMethodAnnotationPlugins.isEmpty())
| + {
| + continue;
| + }
| +
| Signature mis = new MethodSignature(mi);
| MetaData cmdr = retrieval.getComponentMetaData(mis);
| if (cmdr != null)
| {
| - for(T plugin : methodAnnotationPlugins)
| + // only consider the relevant plugins for this method
| + for(T plugin : relevantMethodAnnotationPlugins)
| {
| if (isApplyPhase)
| applyPlugin(plugin, mi, cmdr, handle);
| @@ -297,11 +376,36 @@
| {
| if (smi.isStatic() && smi.isPublic())
| {
| + // let's first find only relevant plugins, through MethodInfo,
before
| + // creating the method signature and retrieving the ComponentMetadata
| + Set<T> relevantStaticMethodAnnotationPlugins = new
HashSet<T>(methodAnnotationPlugins);
| + for(T plugin : methodAnnotationPlugins)
| + {
| + // Can this static method be handled by the plugin?
| + if (!smi.isAnnotationPresent(plugin.getAnnotation()))
| + {
| + // if not then ignore this plugin from processing this method
| + if (log.isTraceEnabled())
| + {
| + log.trace("Plugin " + plugin + " with
annotation " + plugin.getAnnotation().getName() + " is not relevant for static
method " + smi.toString());
| + }
| + // remove this plugin from list of relevant plugins
| + relevantStaticMethodAnnotationPlugins.remove(plugin);
| + }
| + }
| + // if there are no plugins which can handle this static method,
| + // then no use creating a method signature and processing further.
| + // Just move on to the next static method
| + if (relevantStaticMethodAnnotationPlugins.isEmpty())
| + {
| + continue;
| + }
| Signature mis = new MethodSignature(smi);
| MetaData cmdr = retrieval.getComponentMetaData(mis);
| if (cmdr != null)
| {
| - for(T plugin : methodAnnotationPlugins)
| + // use only relevant plugins
| + for(T plugin : relevantStaticMethodAnnotationPlugins)
| {
| if (isApplyPhase)
| applyPlugin(plugin, smi, cmdr, handle);
| @@ -348,11 +452,36 @@
| return;
|
| visitedMethods.add(method);
| + // let's first find only relevant plugins, through MethodInfo, before
| + // creating the method signature and retrieving the ComponentMetadata
| + Set<T> relevantPropertyAnnotationPlugins = new
HashSet<T>(propertyAnnotationPlugins);
| + for(T plugin : propertyAnnotationPlugins)
| + {
| + // Can this getter/setter be handled by the plugin?
| + if (!method.isAnnotationPresent(plugin.getAnnotation()))
| + {
| + // if not then ignore this plugin from processing this getter/setter
| + if (log.isTraceEnabled())
| + {
| + log.trace("Plugin " + plugin + " with annotation "
+ plugin.getAnnotation().getName() + " is not relevant for getter/setter " +
method.toString());
| + }
| + // remove this plugin from list of relevant plugins
| + relevantPropertyAnnotationPlugins.remove(plugin);
| + }
| + }
| + // if there are no plugins which can handle this getter/setter method,
| + // then no use creating a method signature and processing further.
| + if (relevantPropertyAnnotationPlugins.isEmpty())
| + {
| + return;
| + }
| +
| Signature sis = new MethodSignature(method);
| MetaData cmdr = retrieval.getComponentMetaData(sis);
| if (cmdr != null)
| {
| - for(T plugin : propertyAnnotationPlugins)
| + // consider only relevant plugins
| + for(T plugin : relevantPropertyAnnotationPlugins)
| {
| if (isApplyPhase)
| applyPlugin(plugin, pi, cmdr, handle);
|
|
|
|
|
I applied this against my test setup and the profiler now shows that the hotspot that was
identified earlier, no longer exists. I have attached a couple of screenshots to
EJBTHREE-1800 to show the "before" and "after" from the profiler.
Any thoughts about this?
View the original post :
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4223261#...
Reply to the post :
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&a...