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 <[email protected]>
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());
}