You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by ta...@apache.org on 2026/07/28 15:20:57 UTC

(openwebbeans) branch main updated: OWB-1463 - cache by name and optimized loop

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git


The following commit(s) were added to refs/heads/main by this push:
     new 9b7beb729 OWB-1463 - cache by name and optimized loop
9b7beb729 is described below

commit 9b7beb729b26c273baa39e668a751b1eaf85f218
Author: tandraschko <ta...@apache.org>
AuthorDate: Tue Jul 28 17:20:45 2026 +0200

    OWB-1463 - cache by name and optimized loop
---
 .../webbeans/container/InjectionResolver.java      | 79 ++++++++++++++++++----
 1 file changed, 65 insertions(+), 14 deletions(-)

diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java b/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java
index 738e7f608..0c76ec2fc 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java
@@ -103,6 +103,13 @@ public class InjectionResolver
      */
     private volatile Map<Class<?>, Set<Bean<?>>> beansByRawType;
 
+    /**
+     * Index of all beans by their EL name.
+     * Built lazily once the bean set is final (post startup) so name based resolution can look up
+     * candidate beans instead of linearly scanning the whole deployment. Reset in {@link #clearCaches()}.
+     */
+    private volatile Map<String, Set<Bean<?>>> beansByName;
+
     /**
      * Whether the container is in startup mode.
      * Set to {@code false} immediately before the BeforeDeploymentValidation event gets fired.
@@ -147,6 +154,7 @@ public class InjectionResolver
         resolvedBeansByName.clear();
         resolvedBeansByType.clear();
         beansByRawType = null;
+        beansByName = null;
     }
 
     /**
@@ -183,6 +191,32 @@ public class InjectionResolver
         return index;
     }
 
+    private Map<String, Set<Bean<?>>> getBeansByName()
+    {
+        Map<String, Set<Bean<?>>> index = beansByName;
+        if (index == null)
+        {
+            synchronized (this)
+            {
+                index = beansByName;
+                if (index == null)
+                {
+                    index = new HashMap<>();
+                    for (Bean<?> bean : webBeansContext.getBeanManagerImpl().getBeans())
+                    {
+                        String beanName = bean.getName();
+                        if (beanName != null)
+                        {
+                            index.computeIfAbsent(beanName, k -> new HashSet<>()).add(bean);
+                        }
+                    }
+                    beansByName = index;
+                }
+            }
+        }
+        return index;
+    }
+
     /**
      * Check the type of the injection point.
      * <p>
@@ -360,17 +394,29 @@ public class InjectionResolver
             return resolvedComponents;
         }
 
-        resolvedComponents = new HashSet<>();
-        Set<Bean<?>> deployedComponents = webBeansContext.getBeanManagerImpl().getBeans();
-
-        //Finding all beans with given name
-        for (Bean<?> component : deployedComponents)
+        // Once the bean set is final (post startup) the name index answers this directly. The scan
+        // below is O(all beans) per name, which validateBeanNames() repeats for every EL name in the
+        // deployment.
+        if (!startup)
+        {
+            Set<Bean<?>> named = getBeansByName().get(name);
+            // copied because the result is handed out and cached below
+            resolvedComponents = named == null ? new HashSet<>() : new HashSet<>(named);
+        }
+        else
         {
-            if (component.getName() != null)
+            resolvedComponents = new HashSet<>();
+            Set<Bean<?>> deployedComponents = webBeansContext.getBeanManagerImpl().getBeans();
+
+            //Finding all beans with given name
+            for (Bean<?> component : deployedComponents)
             {
-                if (component.getName().equals(name))
+                if (component.getName() != null)
                 {
-                    resolvedComponents.add(component);
+                    if (component.getName().equals(name))
+                    {
+                        resolvedComponents.add(component);
+                    }
                 }
             }
         }
@@ -466,11 +512,13 @@ public class InjectionResolver
 
         boolean returnAll = injectionPointType.equals(Object.class) && currentQualifier;
 
+        // the raw type of the injection point is invariant across the whole scan below
+        Class<?> ipRawType = fastMatching ? ClassUtil.getRawPrimitiveType(injectionPointType) : null;
+
         // Once the bean set is final (post startup) the fast-matching scan is a pure raw-type filter,
         // so we can look up the candidate beans in the index instead of scanning the whole deployment.
         if (fastMatching && !startup && !returnAll)
         {
-            Class<?> ipRawType = ClassUtil.getRawPrimitiveType(injectionPointType);
             if (ipRawType != null)
             {
                 Set<Bean<?>> candidates = getBeansByRawType().get(ipRawType);
@@ -505,13 +553,16 @@ public class InjectionResolver
                 {
                     if (fastMatching)
                     {
-                        for (Type componentApiType : component.getTypes())
+                        if (ipRawType != null)
                         {
-
-                            if (ClassUtil.isRawClassEquals(injectionPointType, componentApiType))
+                            for (Type componentApiType : component.getTypes())
                             {
-                                resolvedComponents.add(component);
-                                break;
+                                Class<?> apiRawType = ClassUtil.getRawPrimitiveType(componentApiType);
+                                if (apiRawType != null && ipRawType.equals(apiRawType))
+                                {
+                                    resolvedComponents.add(component);
+                                    break;
+                                }
                             }
                         }
                     }