From 3f7d4b107e5ffaa3ab773e611ff24f8e22071b8f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 8 Aug 2018 23:53:45 +0200 Subject: [PATCH] Avoid unnecessary annotation introspection on framework classes Issue: SPR-16933 --- .../CacheOperationSourcePointcut.java | 5 ++ .../event/EventListenerMethodProcessor.java | 63 ++++++++++--------- ...actTransactionManagementConfiguration.java | 4 +- .../TransactionAttributeSourcePointcut.java | 6 +- 4 files changed, 46 insertions(+), 32 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java index 9cb731efad..edc01b01a7 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import org.springframework.aop.support.StaticMethodMatcherPointcut; +import org.springframework.cache.CacheManager; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -29,6 +30,7 @@ import org.springframework.util.ObjectUtils; * has an attribute for a given method. * * @author Costin Leau + * @author Juergen Hoeller * @since 3.1 */ @SuppressWarnings("serial") @@ -36,6 +38,9 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut @Override public boolean matches(Method method, Class targetClass) { + if (CacheManager.class.isAssignableFrom(targetClass)) { + return false; + } CacheOperationSource cas = getCacheOperationSource(); return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass))); } diff --git a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java index 6df761728b..7ed6556757 100644 --- a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java @@ -33,6 +33,8 @@ import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; @@ -46,20 +48,30 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** - * Register {@link EventListener} annotated method as individual {@link ApplicationListener} - * instances. + * Registers {@link EventListener} methods as individual {@link ApplicationListener} instances. + * Implements {@link BeanFactoryPostProcessor} (as of 5.1) primarily for early retrieval, + * avoiding AOP checks for this processor bean and its {@link EventListenerFactory} delegates. * * @author Stephane Nicoll * @author Juergen Hoeller * @since 4.2 + * @see EventListenerFactory + * @see DefaultEventListenerFactory */ -public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware { +public class EventListenerMethodProcessor + implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { protected final Log logger = LogFactory.getLog(getClass()); @Nullable private ConfigurableApplicationContext applicationContext; + @Nullable + private ConfigurableListableBeanFactory beanFactory; + + @Nullable + private List eventListenerFactories; + private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator(); private final Set> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64)); @@ -72,22 +84,27 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, this.applicationContext = (ConfigurableApplicationContext) applicationContext; } - private ConfigurableApplicationContext getApplicationContext() { - Assert.state(this.applicationContext != null, "No ApplicationContext set"); - return this.applicationContext; + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + this.beanFactory = beanFactory; + + Map beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false); + List factories = new ArrayList<>(beans.values()); + AnnotationAwareOrderComparator.sort(factories); + this.eventListenerFactories = factories; } @Override public void afterSingletonsInstantiated() { - List factories = getEventListenerFactories(); - ConfigurableApplicationContext context = getApplicationContext(); - String[] beanNames = context.getBeanNamesForType(Object.class); + ConfigurableListableBeanFactory beanFactory = this.beanFactory; + Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); + String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class type = null; try { - type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName); + type = AutoProxyUtils.determineTargetClass(beanFactory, beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. @@ -99,7 +116,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, if (ScopedObject.class.isAssignableFrom(type)) { try { Class targetClass = AutoProxyUtils.determineTargetClass( - context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName)); + beanFactory, ScopedProxyUtils.getTargetBeanName(beanName)); if (targetClass != null) { type = targetClass; } @@ -112,7 +129,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, } } try { - processBean(factories, beanName, type); + processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + @@ -123,21 +140,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, } } - - /** - * Return the {@link EventListenerFactory} instances to use to handle - * {@link EventListener} annotated methods. - */ - protected List getEventListenerFactories() { - Map beans = getApplicationContext().getBeansOfType(EventListenerFactory.class); - List factories = new ArrayList<>(beans.values()); - AnnotationAwareOrderComparator.sort(factories); - return factories; - } - - protected void processBean( - final List factories, final String beanName, final Class targetType) { - + private void processBean(final String beanName, final Class targetType) { if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) { Map annotatedMethods = null; try { @@ -159,7 +162,10 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, } else { // Non-empty set of methods - ConfigurableApplicationContext context = getApplicationContext(); + ConfigurableApplicationContext context = this.applicationContext; + Assert.state(context != null, "No ApplicationContext set"); + List factories = this.eventListenerFactories; + Assert.state(factories != null, "EventListenerFactory List not initialized"); for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { @@ -182,7 +188,6 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, } } - /** * Determine whether the given class is an {@code org.springframework} * bean class that is not annotated as a user or test {@link Component}... diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java index 548400d75a..758f3349b8 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -79,7 +79,7 @@ public abstract class AbstractTransactionManagementConfiguration implements Impo @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - public TransactionalEventListenerFactory transactionalEventListenerFactory() { + public static TransactionalEventListenerFactory transactionalEventListenerFactory() { return new TransactionalEventListenerFactory(); } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java index d2a89da22e..4e2e20706b 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java @@ -20,7 +20,9 @@ import java.io.Serializable; import java.lang.reflect.Method; import org.springframework.aop.support.StaticMethodMatcherPointcut; +import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.lang.Nullable; +import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.ObjectUtils; /** @@ -35,7 +37,9 @@ abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPoi @Override public boolean matches(Method method, Class targetClass) { - if (TransactionalProxy.class.isAssignableFrom(targetClass)) { + if (TransactionalProxy.class.isAssignableFrom(targetClass) || + PlatformTransactionManager.class.isAssignableFrom(targetClass) || + PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource();