summaryrefslogtreecommitdiff
path: root/spring-context
diff options
context:
space:
mode:
authorMarkus Koschany <apo@debian.org>2018-02-09 22:51:36 +0100
committerMarkus Koschany <apo@debian.org>2018-02-09 22:51:36 +0100
commit6dc3d6835b664af0d21e774a5342b90d4417f628 (patch)
treec9f61a10de6abdffba88c8ea6d1dcab09c96603a /spring-context
parent1cb0ad9c5dd218623094b3d6369be7a949094e8d (diff)
New upstream version 4.3.14
Diffstat (limited to 'spring-context')
-rw-r--r--spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java7
-rw-r--r--spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java48
-rw-r--r--spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java36
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java57
-rw-r--r--spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java4
-rw-r--r--spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java11
-rw-r--r--spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java10
-rw-r--r--spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java31
-rw-r--r--spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java5
-rw-r--r--spring-context/src/test/java/org/springframework/cache/interceptor/CacheProxyFactoryBeanTests.java129
-rw-r--r--spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java21
11 files changed, 267 insertions, 92 deletions
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java
index 97cfff7a..1b89ec0e 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 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.
@@ -33,6 +33,7 @@ import org.springframework.cache.interceptor.KeyGenerator;
* for detailed instructions.
*
* @author Chris Beams
+ * @author Stephane Nicoll
* @since 3.1
* @see EnableCaching
* @see CachingConfigurerSupport
@@ -67,8 +68,8 @@ public interface CachingConfigurer {
* Return the {@link CacheResolver} bean to use to resolve regular caches for
* annotation-driven cache management. This is an alternative and more powerful
* option of specifying the {@link CacheManager} to use.
- * <p>If both a {@link #cacheManager()} and {@link #cacheResolver()} are set, the
- * cache manager is ignored.
+ * <p>If both a {@link #cacheManager()} and {@code #cacheResolver()} are set,
+ * the cache manager is ignored.
* <p>Implementations must explicitly declare
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
* <pre class="code">
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
index e1fef7a4..966e8fa5 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.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.
@@ -53,22 +53,20 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
- * Base class for caching aspects, such as the {@link CacheInterceptor}
- * or an AspectJ aspect.
+ * Base class for caching aspects, such as the {@link CacheInterceptor} or an
+ * AspectJ aspect.
*
- * <p>This enables the underlying Spring caching infrastructure to be
- * used easily to implement an aspect for any aspect system.
+ * <p>This enables the underlying Spring caching infrastructure to be used easily
+ * to implement an aspect for any aspect system.
*
- * <p>Subclasses are responsible for calling methods in this class in
- * the correct order.
+ * <p>Subclasses are responsible for calling relevant methods in the correct order.
*
- * <p>Uses the <b>Strategy</b> design pattern. A {@link CacheResolver}
- * implementation will resolve the actual cache(s) to use, and a
- * {@link CacheOperationSource} is used for determining caching
- * operations.
+ * <p>Uses the <b>Strategy</b> design pattern. A {@link CacheOperationSource} is
+ * used for determining caching operations, a {@link KeyGenerator} will build the
+ * cache keys, and a {@link CacheResolver} will resolve the actual cache(s) to use.
*
- * <p>A cache aspect is serializable if its {@code CacheResolver} and
- * {@code CacheOperationSource} are serializable.
+ * <p>Note: A cache aspect is serializable but does not perform any actual caching
+ * after deserialization.
*
* @author Costin Leau
* @author Juergen Hoeller
@@ -132,7 +130,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
/**
* Set the default {@link KeyGenerator} that this cache aspect should delegate to
* if no specific key generator has been set for the operation.
- * <p>The default is a {@link SimpleKeyGenerator}
+ * <p>The default is a {@link SimpleKeyGenerator}.
*/
public void setKeyGenerator(KeyGenerator keyGenerator) {
this.keyGenerator = keyGenerator;
@@ -146,21 +144,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
/**
- * Set the {@link CacheManager} to use to create a default {@link CacheResolver}.
- * Replace the current {@link CacheResolver}, if any.
- * @see #setCacheResolver(CacheResolver)
- * @see SimpleCacheResolver
- */
- public void setCacheManager(CacheManager cacheManager) {
- this.cacheResolver = new SimpleCacheResolver(cacheManager);
- }
-
- /**
* Set the default {@link CacheResolver} that this cache aspect should delegate
* to if no specific cache resolver has been set for the operation.
* <p>The default resolver resolves the caches against their names and the
* default cache manager.
- * @see #setCacheManager(org.springframework.cache.CacheManager)
+ * @see #setCacheManager
* @see SimpleCacheResolver
*/
public void setCacheResolver(CacheResolver cacheResolver) {
@@ -175,6 +163,16 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
/**
+ * Set the {@link CacheManager} to use to create a default {@link CacheResolver}.
+ * Replace the current {@link CacheResolver}, if any.
+ * @see #setCacheResolver
+ * @see SimpleCacheResolver
+ */
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheResolver = new SimpleCacheResolver(cacheManager);
+ }
+
+ /**
* Set the containing {@link BeanFactory} for {@link CacheManager} and other
* service lookups.
* @since 4.3
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java
index 64224f3b..8a457345 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-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.
@@ -19,6 +19,9 @@ package org.springframework.cache.interceptor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.SmartInitializingSingleton;
/**
* Proxy factory bean for simplified declarative caching handling.
@@ -41,24 +44,26 @@ import org.springframework.aop.support.DefaultPointcutAdvisor;
* @see CacheInterceptor
*/
@SuppressWarnings("serial")
-public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
+public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean
+ implements BeanFactoryAware, SmartInitializingSingleton {
- private final CacheInterceptor cachingInterceptor = new CacheInterceptor();
+ private final CacheInterceptor cacheInterceptor = new CacheInterceptor();
private Pointcut pointcut = Pointcut.TRUE;
/**
- * Set the sources used to find cache operations.
+ * Set one or more sources to find cache operations.
+ * @see CacheInterceptor#setCacheOperationSources
*/
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
- this.cachingInterceptor.setCacheOperationSources(cacheOperationSources);
+ this.cacheInterceptor.setCacheOperationSources(cacheOperationSources);
}
/**
- * Set a pointcut, i.e a bean that can cause conditional invocation
- * of the CacheInterceptor depending on method and attributes passed.
- * Note: Additional interceptors are always invoked.
+ * Set a pointcut, i.e. a bean that triggers conditional invocation of the
+ * {@link CacheInterceptor} depending on the method and attributes passed.
+ * <p>Note: Additional interceptors are always invoked.
* @see #setPreInterceptors
* @see #setPostInterceptors
*/
@@ -67,9 +72,20 @@ public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
}
@Override
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.cacheInterceptor.setBeanFactory(beanFactory);
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ this.cacheInterceptor.afterSingletonsInstantiated();
+ }
+
+
+ @Override
protected Object createMainInterceptor() {
- this.cachingInterceptor.afterPropertiesSet();
- return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor);
+ this.cacheInterceptor.afterPropertiesSet();
+ return new DefaultPointcutAdvisor(this.pointcut, this.cacheInterceptor);
}
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java
index adc42223..97867a06 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 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.
@@ -25,7 +25,6 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.BeanUtils;
-import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -40,6 +39,7 @@ import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
+import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -212,6 +212,10 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
scanner.addExcludeFilter(typeFilter);
}
}
+ catch (ClassNotFoundException ex) {
+ parserContext.getReaderContext().warning(
+ "Ignoring non-present type filter class: " + ex, parserContext.extractSource(element));
+ }
catch (Exception ex) {
parserContext.getReaderContext().error(
ex.getMessage(), parserContext.extractSource(element), ex.getCause());
@@ -221,37 +225,34 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
}
@SuppressWarnings("unchecked")
- protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
+ protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader,
+ ParserContext parserContext) throws ClassNotFoundException {
+
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
- try {
- if ("annotation".equals(filterType)) {
- return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
- }
- else if ("assignable".equals(filterType)) {
- return new AssignableTypeFilter(classLoader.loadClass(expression));
- }
- else if ("aspectj".equals(filterType)) {
- return new AspectJTypeFilter(expression, classLoader);
- }
- else if ("regex".equals(filterType)) {
- return new RegexPatternTypeFilter(Pattern.compile(expression));
- }
- else if ("custom".equals(filterType)) {
- Class<?> filterClass = classLoader.loadClass(expression);
- if (!TypeFilter.class.isAssignableFrom(filterClass)) {
- throw new IllegalArgumentException(
- "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
- }
- return (TypeFilter) BeanUtils.instantiateClass(filterClass);
- }
- else {
- throw new IllegalArgumentException("Unsupported filter type: " + filterType);
+ if ("annotation".equals(filterType)) {
+ return new AnnotationTypeFilter((Class<Annotation>) ClassUtils.forName(expression, classLoader));
+ }
+ else if ("assignable".equals(filterType)) {
+ return new AssignableTypeFilter(ClassUtils.forName(expression, classLoader));
+ }
+ else if ("aspectj".equals(filterType)) {
+ return new AspectJTypeFilter(expression, classLoader);
+ }
+ else if ("regex".equals(filterType)) {
+ return new RegexPatternTypeFilter(Pattern.compile(expression));
+ }
+ else if ("custom".equals(filterType)) {
+ Class<?> filterClass = ClassUtils.forName(expression, classLoader);
+ if (!TypeFilter.class.isAssignableFrom(filterClass)) {
+ throw new IllegalArgumentException(
+ "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
}
+ return (TypeFilter) BeanUtils.instantiateClass(filterClass);
}
- catch (ClassNotFoundException ex) {
- throw new FatalBeanException("Type filter class not found: " + expression, ex);
+ else {
+ throw new IllegalArgumentException("Unsupported filter type: " + filterType);
}
}
diff --git a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java
index 4a12a31e..bc72d8de 100644
--- a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java
+++ b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 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.
@@ -183,7 +183,7 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
/**
* Implemented for compatibility with {@link org.springframework.beans.factory.config.PlaceholderConfigurerSupport}.
* @deprecated in favor of {@link #processProperties(ConfigurableListableBeanFactory, ConfigurablePropertyResolver)}
- * @throws UnsupportedOperationException
+ * @throws UnsupportedOperationException in this implementation
*/
@Override
@Deprecated
diff --git a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java
index 0d7090a0..acd14a5c 100644
--- a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java
+++ b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 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.
@@ -84,7 +84,8 @@ import org.springframework.util.StringUtils;
* @see ResourceBundleMessageSource
* @see java.util.ResourceBundle
*/
-public class ReloadableResourceBundleMessageSource extends AbstractResourceBasedMessageSource implements ResourceLoaderAware {
+public class ReloadableResourceBundleMessageSource extends AbstractResourceBasedMessageSource
+ implements ResourceLoaderAware {
private static final String PROPERTIES_SUFFIX = ".properties";
@@ -99,15 +100,15 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
private ResourceLoader resourceLoader = new DefaultResourceLoader();
- /** Cache to hold filename lists per Locale */
+ // Cache to hold filename lists per Locale
private final ConcurrentMap<String, Map<Locale, List<String>>> cachedFilenames =
new ConcurrentHashMap<String, Map<Locale, List<String>>>();
- /** Cache to hold already loaded properties per filename */
+ // Cache to hold already loaded properties per filename
private final ConcurrentMap<String, PropertiesHolder> cachedProperties =
new ConcurrentHashMap<String, PropertiesHolder>();
- /** Cache to hold merged loaded properties per locale */
+ // Cache to hold merged loaded properties per locale
private final ConcurrentMap<Locale, PropertiesHolder> cachedMergedProperties =
new ConcurrentHashMap<Locale, PropertiesHolder>();
diff --git a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java
index d7dce2b5..48250948 100644
--- a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java
+++ b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 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.
@@ -387,9 +387,13 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
}
@Override
- public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) {
+ public boolean needsReload(
+ String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) {
+
if (super.needsReload(baseName, locale, format, loader, bundle, loadTime)) {
- cachedBundleMessageFormats.remove(bundle);
+ synchronized (cachedBundleMessageFormats) {
+ cachedBundleMessageFormats.remove(bundle);
+ }
return true;
}
else {
diff --git a/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java b/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
index ae6384eb..0ea5e137 100644
--- a/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
+++ b/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 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.
@@ -67,6 +67,7 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
setBeanClassLoader(beanClassLoader);
}
+
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
@@ -84,8 +85,10 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
else {
try {
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
- logger.info("Using a reflective load-time weaver for class loader: " +
- this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
+ if (logger.isInfoEnabled()) {
+ logger.info("Using a reflective load-time weaver for class loader: " +
+ this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
+ }
}
catch (IllegalStateException ex) {
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " +
@@ -106,24 +109,26 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(ClassLoader classLoader) {
String name = classLoader.getClass().getName();
try {
- if (name.startsWith("weblogic")) {
- return new WebLogicLoadTimeWeaver(classLoader);
+ if (name.startsWith("org.apache.catalina")) {
+ return new TomcatLoadTimeWeaver(classLoader);
}
else if (name.startsWith("org.glassfish")) {
return new GlassFishLoadTimeWeaver(classLoader);
}
- else if (name.startsWith("org.apache.catalina")) {
- return new TomcatLoadTimeWeaver(classLoader);
- }
else if (name.startsWith("org.jboss")) {
return new JBossLoadTimeWeaver(classLoader);
}
else if (name.startsWith("com.ibm")) {
return new WebSphereLoadTimeWeaver(classLoader);
}
+ else if (name.startsWith("weblogic")) {
+ return new WebLogicLoadTimeWeaver(classLoader);
+ }
}
- catch (IllegalStateException ex) {
- logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
+ catch (Exception ex) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
+ }
}
return null;
}
@@ -131,8 +136,10 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
@Override
public void destroy() {
if (this.loadTimeWeaver instanceof InstrumentationLoadTimeWeaver) {
- logger.info("Removing all registered transformers for class loader: " +
- this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
+ if (logger.isInfoEnabled()) {
+ logger.info("Removing all registered transformers for class loader: " +
+ this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
+ }
((InstrumentationLoadTimeWeaver) this.loadTimeWeaver).removeTransformers();
}
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
index ad9cb8d1..0f6bd36b 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.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.
@@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledExecutorService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -306,7 +307,7 @@ public class ScheduledAnnotationBeanPostProcessor
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) {
- Class<?> targetClass = AopUtils.getTargetClass(bean);
+ Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
new MethodIntrospector.MetadataLookup<Set<Scheduled>>() {
diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheProxyFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheProxyFactoryBeanTests.java
new file mode 100644
index 00000000..0e6a9a1b
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheProxyFactoryBeanTests.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ * 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.springframework.cache.interceptor;
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Test;
+
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration tests for {@link CacheProxyFactoryBean}.
+ *
+ * @author John Blum
+ * @author Juergen Hoeller
+ */
+public class CacheProxyFactoryBeanTests {
+
+ @Test
+ public void configurationClassWithCacheProxyFactoryBean() {
+ try (AnnotationConfigApplicationContext applicationContext =
+ new AnnotationConfigApplicationContext(CacheProxyFactoryBeanConfiguration.class)) {
+ Greeter greeter = applicationContext.getBean("greeter", Greeter.class);
+ assertNotNull(greeter);
+ assertFalse(greeter.isCacheMiss());
+ assertEquals("Hello John!", greeter.greet("John"));
+ assertTrue(greeter.isCacheMiss());
+ assertEquals("Hello Jon!", greeter.greet("Jon"));
+ assertTrue(greeter.isCacheMiss());
+ assertEquals("Hello John!", greeter.greet("John"));
+ assertFalse(greeter.isCacheMiss());
+ assertEquals("Hello World!", greeter.greet());
+ assertTrue(greeter.isCacheMiss());
+ assertEquals("Hello World!", greeter.greet());
+ assertFalse(greeter.isCacheMiss());
+ }
+ }
+
+
+ @Configuration
+ @EnableCaching
+ static class CacheProxyFactoryBeanConfiguration {
+
+ @Bean
+ ConcurrentMapCacheManager cacheManager() {
+ return new ConcurrentMapCacheManager("Greetings");
+ }
+
+ @Bean
+ CacheProxyFactoryBean greeter() {
+ CacheProxyFactoryBean factoryBean = new CacheProxyFactoryBean();
+ factoryBean.setCacheOperationSources(newCacheOperationSource("greet", newCacheOperation("Greetings")));
+ factoryBean.setTarget(new SimpleGreeter());
+ return factoryBean;
+ }
+
+ CacheOperationSource newCacheOperationSource(String methodName, CacheOperation... cacheOperations) {
+ NameMatchCacheOperationSource cacheOperationSource = new NameMatchCacheOperationSource();
+ cacheOperationSource.addCacheMethod(methodName, Arrays.asList(cacheOperations));
+ return cacheOperationSource;
+ }
+
+ CacheableOperation newCacheOperation(String cacheName) {
+ CacheableOperation.Builder builder = new CacheableOperation.Builder();
+ builder.setCacheManager("cacheManager");
+ builder.setCacheName(cacheName);
+ return builder.build();
+ }
+ }
+
+
+ interface Greeter {
+
+ default boolean isCacheHit() {
+ return !isCacheMiss();
+ }
+
+ boolean isCacheMiss();
+
+ void setCacheMiss();
+
+ default String greet() {
+ return greet("World");
+ }
+
+ default String greet(String name) {
+ setCacheMiss();
+ return String.format("Hello %s!", name);
+ }
+ }
+
+
+ static class SimpleGreeter implements Greeter {
+
+ private final AtomicBoolean cacheMiss = new AtomicBoolean(false);
+
+ @Override
+ public boolean isCacheMiss() {
+ return this.cacheMiss.getAndSet(false);
+ }
+
+ @Override
+ public void setCacheMiss() {
+ this.cacheMiss.set(true);
+ }
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
index 6f5a00b2..9b262718 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 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.
@@ -33,6 +33,7 @@ import java.util.TimeZone;
import org.junit.After;
import org.junit.Test;
+import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -179,6 +180,14 @@ public class ScheduledAnnotationBeanPostProcessorTests {
severalFixedRates(context, processorDefinition, targetDefinition);
}
+ @Test
+ public void severalFixedRatesAgainstNestedCglibProxy() {
+ BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
+ BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
+ targetDefinition.setFactoryMethodName("nestedProxy");
+ severalFixedRates(context, processorDefinition, targetDefinition);
+ }
+
private void severalFixedRates(StaticApplicationContext context,
BeanDefinition processorDefinition, BeanDefinition targetDefinition) {
@@ -486,7 +495,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
BeanDefinition targetDefinition = new RootBeanDefinition(ExpressionWithCronTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
- Map<String, String> schedules = new HashMap<String, String>();
+ Map<String, String> schedules = new HashMap<>();
schedules.put("businessHours", businessHoursCronExpression);
context.getBeanFactory().registerSingleton("schedules", schedules);
context.refresh();
@@ -631,6 +640,14 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@Scheduled(fixedRate = 4000, initialDelay = 2000)
public void fixedRate() {
}
+
+ static SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean nestedProxy() {
+ ProxyFactory pf1 = new ProxyFactory(new SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean());
+ pf1.setProxyTargetClass(true);
+ ProxyFactory pf2 = new ProxyFactory(pf1.getProxy());
+ pf2.setProxyTargetClass(true);
+ return (SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean) pf2.getProxy();
+ }
}