Avoid unnecessary annotation introspection on framework classes

Issue: SPR-16933
This commit is contained in:
Juergen Hoeller
2018-08-08 23:53:45 +02:00
parent 4521a79b2d
commit 3f7d4b107e
4 changed files with 46 additions and 32 deletions

View File

@@ -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)));
}

View File

@@ -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<EventListenerFactory> eventListenerFactories;
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
private final Set<Class<?>> 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<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
@Override
public void afterSingletonsInstantiated() {
List<EventListenerFactory> 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<EventListenerFactory> getEventListenerFactories() {
Map<String, EventListenerFactory> beans = getApplicationContext().getBeansOfType(EventListenerFactory.class);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
return factories;
}
protected void processBean(
final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) {
Map<Method, EventListener> 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<EventListenerFactory> 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}...