Skip to content

Commit 0374b2b

Browse files
committed
- NoSuchCacheManagerFailureAnalyzer - analyzer for 'CacheManager' is not found/not unique.
- AbstractNoSuchBeanDefinitionFailureAnalyzer.
1 parent 2d62e9e commit 0374b2b

File tree

10 files changed

+1088
-348
lines changed

10 files changed

+1088
-348
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.springframework.boot.autoconfigure.cache;
1818

1919
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Set;
2022

2123
import org.springframework.beans.factory.InitializingBean;
2224
import org.springframework.beans.factory.ObjectProvider;
@@ -43,7 +45,8 @@
4345
import org.springframework.core.type.AnnotationMetadata;
4446
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
4547
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
46-
import org.springframework.util.Assert;
48+
import org.springframework.util.CollectionUtils;
49+
import org.springframework.util.StringUtils;
4750

4851
/**
4952
* {@link EnableAutoConfiguration Auto-configuration} for the cache abstraction. Creates a
@@ -75,8 +78,9 @@ public CacheManagerCustomizers cacheManagerCustomizers(
7578

7679
@Bean
7780
public CacheManagerValidator cacheAutoConfigurationValidator(
78-
CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
79-
return new CacheManagerValidator(cacheProperties, cacheManager);
81+
CacheProperties cacheProperties,
82+
ObjectProvider<Map<String, CacheManager>> cacheManagers) {
83+
return new CacheManagerValidator(cacheProperties, cacheManagers);
8084
}
8185

8286
@Configuration
@@ -92,27 +96,29 @@ public CacheManagerJpaDependencyConfiguration() {
9296
}
9397

9498
/**
95-
* Bean used to validate that a CacheManager exists and provide a more meaningful
96-
* exception.
99+
* Bean used to validate that a CacheManager exists and it unique.
97100
*/
98101
static class CacheManagerValidator implements InitializingBean {
99102

100103
private final CacheProperties cacheProperties;
101104

102-
private final ObjectProvider<CacheManager> cacheManager;
105+
private final Map<String, CacheManager> cacheManagers;
103106

104107
CacheManagerValidator(CacheProperties cacheProperties,
105-
ObjectProvider<CacheManager> cacheManager) {
108+
ObjectProvider<Map<String, CacheManager>> cacheManagers) {
106109
this.cacheProperties = cacheProperties;
107-
this.cacheManager = cacheManager;
110+
this.cacheManagers = cacheManagers.getIfAvailable();
108111
}
109112

110113
@Override
111114
public void afterPropertiesSet() {
112-
Assert.notNull(this.cacheManager.getIfAvailable(),
113-
() -> "No cache manager could "
114-
+ "be auto-configured, check your configuration (caching "
115-
+ "type is '" + this.cacheProperties.getType() + "')");
115+
if (CollectionUtils.isEmpty(this.cacheManagers)) {
116+
throw new NoSuchCacheManagerException(this.cacheProperties);
117+
}
118+
if (this.cacheManagers.size() > 1) {
119+
throw new NoUniqueCacheManagerException(this.cacheManagers.keySet(),
120+
this.cacheProperties);
121+
}
116122
}
117123

118124
}
@@ -134,4 +140,52 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) {
134140

135141
}
136142

143+
/**
144+
* Exception thrown when {@link org.springframework.cache.CacheManager} implementation
145+
* are not specified.
146+
*/
147+
static class NoSuchCacheManagerException extends RuntimeException {
148+
149+
private final CacheProperties properties;
150+
151+
NoSuchCacheManagerException(CacheProperties properties) {
152+
super(String.format("No qualifying bean of type '%s' available",
153+
CacheManager.class.getName()));
154+
this.properties = properties;
155+
}
156+
157+
NoSuchCacheManagerException(String message, CacheProperties properties) {
158+
super(message);
159+
this.properties = properties;
160+
}
161+
162+
CacheProperties getProperties() {
163+
return this.properties;
164+
}
165+
166+
}
167+
168+
/**
169+
* Exception thrown when multiple {@link org.springframework.cache.CacheManager}
170+
* implementations are available with no way to know which implementation should be
171+
* used.
172+
*/
173+
static class NoUniqueCacheManagerException extends NoSuchCacheManagerException {
174+
175+
private final Set<String> beanNames;
176+
177+
NoUniqueCacheManagerException(Set<String> beanNames, CacheProperties properties) {
178+
super(String.format(
179+
"expected single matching bean of type '%s' but found " + "%d: %s",
180+
CacheManager.class.getName(), beanNames.size(),
181+
StringUtils.collectionToCommaDelimitedString(beanNames)), properties);
182+
this.beanNames = beanNames;
183+
}
184+
185+
Set<String> getBeanNames() {
186+
return this.beanNames;
187+
}
188+
189+
}
190+
137191
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.cache;
18+
19+
import java.util.Set;
20+
21+
import org.springframework.beans.BeansException;
22+
import org.springframework.beans.factory.BeanFactory;
23+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
24+
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
26+
import org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzerSupport;
27+
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
28+
import org.springframework.boot.diagnostics.FailureAnalysis;
29+
import org.springframework.cache.CacheManager;
30+
import org.springframework.util.Assert;
31+
import org.springframework.util.CollectionUtils;
32+
import org.springframework.util.StringUtils;
33+
34+
/**
35+
* An {@link AbstractFailureAnalyzer} for
36+
* {@link CacheAutoConfiguration.NoSuchCacheManagerException}.
37+
*
38+
* @author Dmytro Nosan
39+
*/
40+
class NoSuchCacheManagerFailureAnalyzer extends
41+
NoSuchBeanDefinitionFailureAnalyzerSupport<CacheAutoConfiguration.NoSuchCacheManagerException> {
42+
43+
private ConfigurableListableBeanFactory beanFactory;
44+
45+
@Override
46+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
47+
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
48+
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
49+
super.setBeanFactory(beanFactory);
50+
}
51+
52+
@Override
53+
public FailureAnalysis analyze(Throwable failure) {
54+
CacheAutoConfiguration.NoUniqueCacheManagerException cause = findCause(failure,
55+
CacheAutoConfiguration.NoUniqueCacheManagerException.class);
56+
if (cause != null) {
57+
return analyzeNoUniqueCacheManagerException(cause);
58+
}
59+
return super.analyze(failure);
60+
}
61+
62+
@Override
63+
protected BeanMetadata getBeanMetadata(Throwable rootFailure,
64+
CacheAutoConfiguration.NoSuchCacheManagerException cause) {
65+
return new BeanMetadata(CacheManager.class);
66+
}
67+
68+
private FailureAnalysis analyzeNoUniqueCacheManagerException(
69+
CacheAutoConfiguration.NoUniqueCacheManagerException cause) {
70+
Set<String> beanNames = cause.getBeanNames();
71+
if (CollectionUtils.isEmpty(beanNames)) {
72+
return null;
73+
}
74+
StringBuilder description = new StringBuilder();
75+
description.append(String.format("Found %d beans of the type " + "'%s'%n",
76+
beanNames.size(), CacheManager.class.getName()));
77+
for (String beanName : beanNames) {
78+
try {
79+
BeanDefinition definition = this.beanFactory
80+
.getMergedBeanDefinition(beanName);
81+
if (StringUtils.hasText(definition.getFactoryMethodName())) {
82+
description.append(
83+
String.format("\t- '%s': defined by method '%s' in %s%n",
84+
beanName, definition.getFactoryMethodName(),
85+
definition.getResourceDescription()));
86+
}
87+
else {
88+
description.append(String.format("\t- '%s': defined in %s%n",
89+
beanName, definition.getResourceDescription()));
90+
}
91+
}
92+
catch (NoSuchBeanDefinitionException ex) {
93+
description.append(String.format(
94+
"\t- '%s': a programmatically registered singleton", beanName));
95+
}
96+
}
97+
return new FailureAnalysis(description.toString(),
98+
"Consider marking one of the beans as @Primary, updating the consumer to"
99+
+ " accept multiple beans, or using @Qualifier to identify the"
100+
+ " bean that should be consumed",
101+
cause);
102+
}
103+
104+
}

0 commit comments

Comments
 (0)