diff options
author | Markus Koschany <apo@debian.org> | 2018-02-09 22:51:36 +0100 |
---|---|---|
committer | Markus Koschany <apo@debian.org> | 2018-02-09 22:51:36 +0100 |
commit | 6dc3d6835b664af0d21e774a5342b90d4417f628 (patch) | |
tree | c9f61a10de6abdffba88c8ea6d1dcab09c96603a /spring-context | |
parent | 1cb0ad9c5dd218623094b3d6369be7a949094e8d (diff) |
New upstream version 4.3.14
Diffstat (limited to 'spring-context')
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(); + } } |