From 9f4f07bcfd87d830318f1ead10ae27dbcc149615 Mon Sep 17 00:00:00 2001 From: Rick Hogge Date: Thu, 10 Aug 2017 23:18:48 -0500 Subject: [PATCH] INT-4327: Optimize Bean Post Processors JIRA: https://jira.spring.io/browse/INT-4327 To avoid reflection and annotation processing overhead on the bean classes when we deal with non-singleton beans and there is really no any messaging on the bean class, store bean classes to the local cache to skip them in the future when `BPP` is applied for request/prototype beans * Simple code style polishing **Cherry-pick to 4.3.x** --- .../PublisherAnnotationBeanPostProcessor.java | 18 +++++++++++++++++- .../MessagingAnnotationPostProcessor.java | 13 +++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java index e461a6240d..bb1bc30f5a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,10 @@ package org.springframework.integration.aop; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyConfig; import org.springframework.aop.framework.ProxyFactory; @@ -37,6 +41,8 @@ import org.springframework.util.ClassUtils; * @author Mark Fisher * @author Gary Russell * @author Artem Bilan + * @author Rick Hogge + * * @since 2.0 */ @SuppressWarnings("serial") @@ -53,6 +59,9 @@ public class PublisherAnnotationBeanPostProcessor extends ProxyConfig private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + private final Set> nonApplicableCache = + Collections.newSetFromMap(new ConcurrentHashMap, Boolean>(256)); + /** * Set the default channel where Messages should be sent if the annotation * itself does not provide a channel. @@ -101,6 +110,12 @@ public class PublisherAnnotationBeanPostProcessor extends ProxyConfig return bean; } + // the set will hold records of prior class scans and will contain the bean classes that can not + // be assigned to the Advisor interface and therefore can be short circuited + if (this.nonApplicableCache.contains(targetClass)) { + return bean; + } + if (AopUtils.canApply(this.advisor, targetClass)) { if (bean instanceof Advised) { ((Advised) bean).addAdvisor(this.advisor); @@ -116,6 +131,7 @@ public class PublisherAnnotationBeanPostProcessor extends ProxyConfig } else { // cannot apply advisor + nonApplicableCache.add(targetClass); return bean; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java index 82c89121ff..755f30a868 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -71,6 +72,7 @@ import org.springframework.util.StringUtils; * @author Marius Bogoevici * @author Artem Bilan * @author Gary Russell + * @author Rick Hogge */ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean, SmartInitializingSingleton { @@ -84,6 +86,8 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean private ConfigurableListableBeanFactory beanFactory; + private final Set> noAnnotationsCache = + Collections.newSetFromMap(new ConcurrentHashMap, Boolean>(256)); @Override public void setBeanFactory(BeanFactory beanFactory) { @@ -151,6 +155,11 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean Class beanClass = AopUtils.getTargetClass(bean); + // the set will hold records of prior class scans and indicate if no messaging annotations were found + if (this.noAnnotationsCache.contains(beanClass)) { + return bean; + } + ReflectionUtils.doWithMethods(beanClass, method -> { Map, List> annotationChains = new HashMap<>(); for (Class annotationType : @@ -168,6 +177,10 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean List annotations = entry.getValue(); processAnnotationTypeOnMethod(bean, beanName, method, annotationType, annotations); } + + if (annotationChains.size() == 0) { + noAnnotationsCache.add(beanClass); + } }, ReflectionUtils.USER_DECLARED_METHODS); return bean;