You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2013/02/27 10:58:07 UTC

svn commit: r1450699 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/component/bean/ test/java/org/apache/camel/component/bean/

Author: davsclaus
Date: Wed Feb 27 09:58:07 2013
New Revision: 1450699

URL: http://svn.apache.org/r1450699
Log:
CAMEL-6043: Bean language/expression with OGNL now uses BeanInfo cache to speedup evaluations at runtime using the same class types (cache hit). Let the cache be controlled by the bean component and ensure its lifecycle is controlled by the component.

Added:
    camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfoCacheKey.java
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanComponent.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTestRunner.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanComponent.java?rev=1450699&r1=1450698&r2=1450699&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanComponent.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanComponent.java Wed Feb 27 09:58:07 2013
@@ -22,6 +22,9 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.Processor;
 import org.apache.camel.impl.DefaultComponent;
 import org.apache.camel.impl.ProcessorEndpoint;
+import org.apache.camel.util.LRUSoftCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The <a href="http://camel.apache.org/bean.html">Bean Component</a>
@@ -31,6 +34,11 @@ import org.apache.camel.impl.ProcessorEn
  */
 public class BeanComponent extends DefaultComponent {
 
+    private static final transient Logger LOG = LoggerFactory.getLogger(BeanComponent.class);
+    // use an internal soft cache for BeanInfo as they are costly to introspect
+    // for example the bean language using OGNL expression runs much faster reusing the BeanInfo from this cache
+    private final LRUSoftCache<BeanInfoCacheKey, BeanInfo> cache = new LRUSoftCache<BeanInfoCacheKey, BeanInfo>(1000);
+
     public BeanComponent() {
     }
     
@@ -67,4 +75,20 @@ public class BeanComponent extends Defau
     protected BeanEndpoint createEndpoint(String uri, BeanProcessor processor) {
         return new BeanEndpoint(uri, this, processor);
     }
+
+    BeanInfo getBeanInfoFromCache(BeanInfoCacheKey key) {
+        return cache.get(key);
+    }
+
+    void addBeanInfoToCache(BeanInfoCacheKey key, BeanInfo beanInfo) {
+        cache.put(key, beanInfo);
+    }
+
+    @Override
+    protected void doShutdown() throws Exception {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Clearing BeanInfo cache[size={}, hits={}, misses={}, evicted={}]", new Object[]{cache.size(), cache.getHits(), cache.getMisses(), cache.getEvicted()});
+        }
+        cache.clear();
+    }
 }

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java?rev=1450699&r1=1450698&r2=1450699&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java Wed Feb 27 09:58:07 2013
@@ -57,11 +57,11 @@ import org.slf4j.LoggerFactory;
  * introspection and annotations together with some useful sensible defaults
  */
 public class BeanInfo {
-    public static final String BEAN_INFO_CACHE_REGISTRY_KEY = "CamelBeanInfoCache";
     private static final transient Logger LOG = LoggerFactory.getLogger(BeanInfo.class);
     private static final String CGLIB_CLASS_SEPARATOR = "$$";
     private static final List<Method> EXCLUDED_METHODS = new ArrayList<Method>();
     private final CamelContext camelContext;
+    private final BeanComponent component;
     private final Class<?> type;
     private final ParameterMappingStrategy strategy;
     private final MethodInfo defaultMethod;
@@ -103,22 +103,24 @@ public class BeanInfo {
         this.camelContext = camelContext;
         this.type = type;
         this.strategy = strategy;
+        this.component = camelContext.getComponent("bean", BeanComponent.class);
 
-        Map<CacheKey, BeanInfo> cache = (Map<CacheKey, BeanInfo>) camelContext.getRegistry().lookupByNameAndType(BEAN_INFO_CACHE_REGISTRY_KEY, Map.class);
-        CacheKey cacheKey = new CacheKey(type, explicitMethod, strategy);
-        if (cache != null) {
-            BeanInfo beanInfo = cache.get(cacheKey);
-            if (beanInfo != null) {
-                defaultMethod = beanInfo.defaultMethod;
-                operations = beanInfo.operations;
-                operationsWithBody = beanInfo.operationsWithBody;
-                operationsWithNoBody = beanInfo.operationsWithNoBody;
-                operationsWithCustomAnnotation = beanInfo.operationsWithCustomAnnotation;
-                operationsWithHandlerAnnotation = beanInfo.operationsWithHandlerAnnotation;
-                methodMap = beanInfo.methodMap;
-                return;
-            }
+        final BeanInfoCacheKey key = new BeanInfoCacheKey(type, explicitMethod);
+
+        // lookup if we have a bean info cache
+        BeanInfo beanInfo = component.getBeanInfoFromCache(key);
+        if (beanInfo != null) {
+            // copy the values from the cache we need
+            defaultMethod = beanInfo.defaultMethod;
+            operations = beanInfo.operations;
+            operationsWithBody = beanInfo.operationsWithBody;
+            operationsWithNoBody = beanInfo.operationsWithNoBody;
+            operationsWithCustomAnnotation = beanInfo.operationsWithCustomAnnotation;
+            operationsWithHandlerAnnotation = beanInfo.operationsWithHandlerAnnotation;
+            methodMap = beanInfo.methodMap;
+            return;
         }
+
         if (explicitMethod != null) {
             // must be a valid method
             if (!isValidMethod(type, explicitMethod)) {
@@ -147,10 +149,9 @@ public class BeanInfo {
         operationsWithCustomAnnotation = Collections.unmodifiableList(operationsWithCustomAnnotation);
         operationsWithHandlerAnnotation = Collections.unmodifiableList(operationsWithHandlerAnnotation);
         methodMap = Collections.unmodifiableMap(methodMap);
-        
-        if (cache != null) {
-            cache.put(cacheKey, this);
-        }
+
+        // add new bean info to cache
+        component.addBeanInfoToCache(key, this);
     }
 
     public Class<?> getType() {
@@ -1025,49 +1026,5 @@ public class BeanInfo {
 
         return null;
     }
-    
-    private static final class CacheKey {
-        private final Class<?> type;
-        private final Method explicitMethod;
-        private final Class<? extends ParameterMappingStrategy> strategyClass;
-
-        public CacheKey(Class<?> type, Method explicitMethod, ParameterMappingStrategy strategy) {
-            this.type = type;
-            this.explicitMethod = explicitMethod;
-            this.strategyClass = strategy.getClass();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            CacheKey cacheKey = (CacheKey) o;
-
-            if (explicitMethod != null ? !explicitMethod.equals(cacheKey.explicitMethod) : cacheKey.explicitMethod != null) {
-                return false;
-            }
-            if (!strategyClass.equals(cacheKey.strategyClass)) {
-                return false;
-            }
-            if (!type.equals(cacheKey.type)) {
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = type.hashCode();
-            result = 31 * result + (explicitMethod != null ? explicitMethod.hashCode() : 0);
-            result = 31 * result + strategyClass.hashCode();
-            return result;
-        }
-    }
 
 }

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfoCacheKey.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfoCacheKey.java?rev=1450699&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfoCacheKey.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfoCacheKey.java Wed Feb 27 09:58:07 2013
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import java.lang.reflect.Method;
+
+/**
+ * A key used for caching {@link BeanInfo} by the {@link BeanComponent}
+ */
+public final class BeanInfoCacheKey {
+
+    private final Class<?> type;
+    private final Method explicitMethod;
+
+    public BeanInfoCacheKey(Class<?> type, Method explicitMethod) {
+        this.type = type;
+        this.explicitMethod = explicitMethod;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        BeanInfoCacheKey that = (BeanInfoCacheKey) o;
+
+        if (explicitMethod != null ? !explicitMethod.equals(that.explicitMethod) : that.explicitMethod != null) {
+            return false;
+        }
+        if (!type.equals(that.type)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = type.hashCode();
+        result = 31 * result + (explicitMethod != null ? explicitMethod.hashCode() : 0);
+        return result;
+    }
+}

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTestRunner.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTestRunner.java?rev=1450699&r1=1450698&r2=1450699&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTestRunner.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTestRunner.java Wed Feb 27 09:58:07 2013
@@ -27,7 +27,7 @@ import org.apache.camel.impl.SimpleRegis
 import org.apache.camel.spi.Registry;
 
 public final class CamelSimpleExpressionPerfTestRunner {
-    private static final int MESSAGE_LOOP_COUNT = 10000;
+    private static final int MESSAGE_LOOP_COUNT = 1000;
     private static final int TEST_EXECUTION_COUNT = 5;
     
     private CamelSimpleExpressionPerfTestRunner() {
@@ -37,10 +37,7 @@ public final class CamelSimpleExpression
     public static void main(String[] args) throws Exception {
         long bodyOnly = executePerformanceTest(new SimpleRegistry(), "${body}");
         long bodyProperty = executePerformanceTest(new SimpleRegistry(), "${body[p]}");
-
-        SimpleRegistry registry = new SimpleRegistry();
-        registry.put(BeanInfo.BEAN_INFO_CACHE_REGISTRY_KEY, new HashMap());
-        long bodyPropertyWithCache = executePerformanceTest(registry, "${body[p]}");
+        long bodyPropertyWithCache = executePerformanceTest(new SimpleRegistry(), "${body[p]}");
 
         System.out.printf("${body}: %dms%n", bodyOnly);
         System.out.printf("${body[p]} : %dms%n", bodyProperty);
@@ -74,6 +71,8 @@ public final class CamelSimpleExpression
             totalNsDuration += System.nanoTime() - tick;
         }
 
+        ctx.stop();
+
         // Return the average duration in milliseconds
         return totalNsDuration / TEST_EXECUTION_COUNT / 1000 / 1000;
     }