Avoid unnecessary annotation introspection on framework classes
Issue: SPR-16933
This commit is contained in:
parent
4521a79b2d
commit
3f7d4b107e
|
@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
@ -29,6 +30,7 @@ import org.springframework.util.ObjectUtils;
|
||||||
* has an attribute for a given method.
|
* has an attribute for a given method.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@ -36,6 +38,9 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Method method, Class<?> targetClass) {
|
public boolean matches(Method method, Class<?> targetClass) {
|
||||||
|
if (CacheManager.class.isAssignableFrom(targetClass)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
CacheOperationSource cas = getCacheOperationSource();
|
CacheOperationSource cas = getCacheOperationSource();
|
||||||
return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
|
return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ import org.springframework.aop.scope.ScopedProxyUtils;
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.beans.factory.BeanInitializationException;
|
import org.springframework.beans.factory.BeanInitializationException;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
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.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
|
@ -46,20 +48,30 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register {@link EventListener} annotated method as individual {@link ApplicationListener}
|
* Registers {@link EventListener} methods as individual {@link ApplicationListener} instances.
|
||||||
* 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 Stephane Nicoll
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 4.2
|
* @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());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ConfigurableApplicationContext applicationContext;
|
private ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ConfigurableListableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private List<EventListenerFactory> eventListenerFactories;
|
||||||
|
|
||||||
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
|
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
|
||||||
|
|
||||||
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
|
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
|
||||||
|
@ -72,22 +84,27 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||||
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
|
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigurableApplicationContext getApplicationContext() {
|
@Override
|
||||||
Assert.state(this.applicationContext != null, "No ApplicationContext set");
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||||
return this.applicationContext;
|
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
|
@Override
|
||||||
public void afterSingletonsInstantiated() {
|
public void afterSingletonsInstantiated() {
|
||||||
List<EventListenerFactory> factories = getEventListenerFactories();
|
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
|
||||||
ConfigurableApplicationContext context = getApplicationContext();
|
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
|
||||||
String[] beanNames = context.getBeanNamesForType(Object.class);
|
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
|
||||||
for (String beanName : beanNames) {
|
for (String beanName : beanNames) {
|
||||||
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
|
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
|
||||||
Class<?> type = null;
|
Class<?> type = null;
|
||||||
try {
|
try {
|
||||||
type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
|
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
|
// 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)) {
|
if (ScopedObject.class.isAssignableFrom(type)) {
|
||||||
try {
|
try {
|
||||||
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
|
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
|
||||||
context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));
|
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
|
||||||
if (targetClass != null) {
|
if (targetClass != null) {
|
||||||
type = targetClass;
|
type = targetClass;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +129,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
processBean(factories, beanName, type);
|
processBean(beanName, type);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new BeanInitializationException("Failed to process @EventListener " +
|
throw new BeanInitializationException("Failed to process @EventListener " +
|
||||||
|
@ -123,21 +140,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processBean(final String beanName, final Class<?> targetType) {
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
|
|
||||||
if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) {
|
if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) {
|
||||||
Map<Method, EventListener> annotatedMethods = null;
|
Map<Method, EventListener> annotatedMethods = null;
|
||||||
try {
|
try {
|
||||||
|
@ -159,7 +162,10 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Non-empty set of methods
|
// 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 (Method method : annotatedMethods.keySet()) {
|
||||||
for (EventListenerFactory factory : factories) {
|
for (EventListenerFactory factory : factories) {
|
||||||
if (factory.supportsMethod(method)) {
|
if (factory.supportsMethod(method)) {
|
||||||
|
@ -182,7 +188,6 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the given class is an {@code org.springframework}
|
* Determine whether the given class is an {@code org.springframework}
|
||||||
* bean class that is not annotated as a user or test {@link Component}...
|
* bean class that is not annotated as a user or test {@link Component}...
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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)
|
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
public TransactionalEventListenerFactory transactionalEventListenerFactory() {
|
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
|
||||||
return new TransactionalEventListenerFactory();
|
return new TransactionalEventListenerFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,9 @@ import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +37,9 @@ abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPoi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Method method, Class<?> targetClass) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
TransactionAttributeSource tas = getTransactionAttributeSource();
|
TransactionAttributeSource tas = getTransactionAttributeSource();
|
||||||
|
|
Loading…
Reference in New Issue