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

ggrzybek pushed a commit to branch camel-2.25.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-2.25.x by this push:
     new 5698b0d  [CAMEL-15061] Cache failed attempts to load classes to 
greatly improve performance (#3825)
5698b0d is described below

commit 5698b0df3d16c30aae8561794a166f543c036bb6
Author: Grzegorz Grzybek <gr.grzy...@gmail.com>
AuthorDate: Thu May 14 12:57:10 2020 +0200

    [CAMEL-15061] Cache failed attempts to load classes to greatly improve 
performance (#3825)
---
 .../apache/camel/impl/DefaultFactoryFinder.java    | 21 ++++++++++++++-
 .../camel/impl/DefaultFactoryFinderTest.java       | 31 ++++++++++++++++++++++
 .../blueprint/BlueprintContainerRegistry.java      | 17 +++++++++++-
 3 files changed, 67 insertions(+), 2 deletions(-)

diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java 
b/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
index 3ed501e..d8721dd 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
@@ -40,6 +40,7 @@ import org.apache.camel.util.IOHelper;
 public class DefaultFactoryFinder implements FactoryFinder {
 
     private final ConcurrentMap<String, Class<?>> classMap = new 
ConcurrentHashMap<>();
+    private final ConcurrentMap<String, Exception> classesNotFound = new 
ConcurrentHashMap<>();
     private final ClassResolver classResolver;
     private final String path;
 
@@ -166,20 +167,38 @@ public class DefaultFactoryFinder implements 
FactoryFinder {
      */
     protected Class<?> addToClassMap(String key, ClassSupplier 
mappingFunction) throws ClassNotFoundException, IOException {
         try {
-            return classMap.computeIfAbsent(key, new Function<String, 
Class<?>>() {
+            if (classesNotFound.containsKey(key)) {
+                Exception e = classesNotFound.get(key);
+                if (e == null) {
+                    return null;
+                } else {
+                    throw new WrappedRuntimeException(e);
+                }
+            }
+
+            Class<?> suppliedClass = classMap.computeIfAbsent(key, new 
Function<String, Class<?>>() {
                 @Override
                 public Class<?> apply(String classKey) {
                     try {
                         return mappingFunction.get();
                     } catch (ClassNotFoundException e) {
+                        classesNotFound.put(key, e);
                         throw new WrappedRuntimeException(e);
                     } catch (NoFactoryAvailableException e) {
+                        classesNotFound.put(key, e);
                         throw new WrappedRuntimeException(e);
                     } catch (IOException e) {
                         throw new WrappedRuntimeException(e);
                     }
                 }
             });
+
+            if (suppliedClass == null) {
+                // mark the key as non-resolvable to prevent pointless 
searching
+                classesNotFound.put(key, null);
+            }
+
+            return suppliedClass;
         } catch (WrappedRuntimeException e) {
             if (e.getCause() instanceof ClassNotFoundException) {
                 throw (ClassNotFoundException)e.getCause();
diff --git 
a/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java 
b/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
index 88f67ee..b34170b 100644
--- 
a/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
@@ -34,6 +34,8 @@ import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 public class DefaultFactoryFinderTest {
@@ -74,6 +76,35 @@ public class DefaultFactoryFinderTest {
     }
 
     @Test
+    public void shouldCacheFailedAttemptToResolveClass() throws IOException {
+        final ClassResolver classResolver = mock(ClassResolver.class);
+
+        final String properties = "class=" + TestImplA.class.getName();
+
+        
when(classResolver.loadResourceAsStream("/org/apache/camel/impl/TestImplA"))
+                .thenAnswer((invocation) -> new 
ByteArrayInputStream(properties.getBytes()));
+
+        
when(classResolver.resolveClass(TestImplA.class.getName())).thenReturn(null);
+
+        final DefaultFactoryFinder factoryFinder = new 
DefaultFactoryFinder(classResolver, TEST_RESOURCE_PATH);
+
+        try {
+            factoryFinder.findClass("TestImplA", null);
+            fail("Should have thrown ClassNotFoundException");
+        } catch (final ClassNotFoundException e) {
+            assertEquals(TestImplA.class.getName(), e.getMessage());
+        }
+        try {
+            factoryFinder.findClass("TestImplA", null);
+            fail("Should have thrown ClassNotFoundException");
+        } catch (final ClassNotFoundException e) {
+            assertEquals(TestImplA.class.getName(), e.getMessage());
+        }
+
+        verify(classResolver, 
times(1)).resolveClass(TestImplA.class.getName());
+    }
+
+    @Test
     public void shouldComplainIfInstanceTypeIsNotAsExpected() throws 
ClassNotFoundException, IOException {
         final Injector injector = mock(Injector.class);
 
diff --git 
a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintContainerRegistry.java
 
b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintContainerRegistry.java
index 9a60984..cde87dd 100644
--- 
a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintContainerRegistry.java
+++ 
b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintContainerRegistry.java
@@ -16,10 +16,12 @@
  */
 package org.apache.camel.blueprint;
 
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.spi.Registry;
@@ -34,6 +36,8 @@ public class BlueprintContainerRegistry implements Registry {
 
     private final BlueprintContainer blueprintContainer;
 
+    private final Map<Class<?>, Map<String, Class<?>>> 
perBlueprintContainerCache = new ConcurrentHashMap<>();
+
     public BlueprintContainerRegistry(BlueprintContainer blueprintContainer) {
         this.blueprintContainer = blueprintContainer;
     }
@@ -71,13 +75,24 @@ public class BlueprintContainerRegistry implements Registry 
{
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public <T> Map<String, T> findByTypeWithName(Class<T> type) {
-        return lookupByType(blueprintContainer, type);
+        if (perBlueprintContainerCache.containsKey(type)) {
+            return (Map<String, T>) perBlueprintContainerCache.get(type);
+        }
+        Map<String, T> result = lookupByType(blueprintContainer, type);
+        perBlueprintContainerCache.put(type, (Map<String, Class<?>>) result);
+        return result;
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public <T> Set<T> findByType(Class<T> type) {
+        if (perBlueprintContainerCache.containsKey(type)) {
+            return new HashSet<T>((Collection<? extends T>) 
perBlueprintContainerCache.get(type).values());
+        }
         Map<String, T> map = lookupByType(blueprintContainer, type);
+        perBlueprintContainerCache.put(type, (Map<String, Class<?>>) map);
         return new HashSet<>(map.values());
     }
 

Reply via email to