[jboss-dev-forums] [Design the new POJO MicroContainer] - Improving the process of applying AnnotationPlugins on MC be
jaikiran
do-not-reply at jboss.com
Fri Apr 3 07:42:01 EDT 2009
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#4223261
Reply to the post : http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=4223261
More information about the jboss-dev-forums
mailing list