|
16 | 16 |
|
17 | 17 | package org.springframework.boot.autoconfigure.data.mongo; |
18 | 18 |
|
| 19 | +import java.util.Arrays; |
| 20 | +import java.util.List; |
| 21 | + |
19 | 22 | import com.mongodb.ClientSessionOptions; |
20 | 23 | import com.mongodb.DB; |
21 | 24 | import com.mongodb.MongoClient; |
22 | 25 | import com.mongodb.client.ClientSession; |
23 | 26 | import com.mongodb.client.MongoDatabase; |
24 | 27 |
|
| 28 | +import org.springframework.beans.factory.ObjectProvider; |
25 | 29 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
26 | 30 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
| 31 | +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; |
27 | 32 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
28 | 33 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
29 | 34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
| 35 | +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration.AnySyncMongoClientAvailable; |
30 | 36 | import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; |
31 | 37 | import org.springframework.boot.autoconfigure.mongo.MongoProperties; |
32 | 38 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
33 | 39 | import org.springframework.context.annotation.Bean; |
| 40 | +import org.springframework.context.annotation.Conditional; |
34 | 41 | import org.springframework.context.annotation.Configuration; |
35 | 42 | import org.springframework.context.annotation.Import; |
36 | 43 | import org.springframework.dao.DataAccessException; |
37 | 44 | import org.springframework.dao.support.PersistenceExceptionTranslator; |
38 | 45 | import org.springframework.data.mongodb.MongoDbFactory; |
39 | 46 | import org.springframework.data.mongodb.core.MongoTemplate; |
| 47 | +import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; |
40 | 48 | import org.springframework.data.mongodb.core.SimpleMongoDbFactory; |
41 | 49 | import org.springframework.data.mongodb.core.convert.DbRefResolver; |
42 | 50 | import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; |
|
63 | 71 | * @author Phillip Webb |
64 | 72 | * @author Eddú Meléndez |
65 | 73 | * @author Stephane Nicoll |
| 74 | + * @author Christoph Strobl |
66 | 75 | * @since 1.1.0 |
67 | 76 | */ |
68 | 77 | @Configuration |
69 | 78 | @ConditionalOnClass({ MongoClient.class, MongoTemplate.class }) |
70 | | -@ConditionalOnBean(MongoClient.class) |
| 79 | +@Conditional(AnySyncMongoClientAvailable.class) |
71 | 80 | @EnableConfigurationProperties(MongoProperties.class) |
72 | 81 | @Import(MongoDataConfiguration.class) |
73 | 82 | @AutoConfigureAfter(MongoAutoConfiguration.class) |
74 | 83 | public class MongoDataAutoConfiguration { |
75 | 84 |
|
76 | 85 | private final MongoProperties properties; |
77 | 86 |
|
78 | | - public MongoDataAutoConfiguration(MongoProperties properties) { |
| 87 | + private final MongoDbFactoryFactory dbFactoryFactory; |
| 88 | + |
| 89 | + public MongoDataAutoConfiguration(ObjectProvider<MongoClient> mongoClientProvider, |
| 90 | + ObjectProvider<com.mongodb.client.MongoClient> mongoClientClientProvider, |
| 91 | + MongoProperties properties) { |
| 92 | + |
79 | 93 | this.properties = properties; |
| 94 | + this.dbFactoryFactory = new MongoDbFactoryFactory(mongoClientProvider, |
| 95 | + mongoClientClientProvider); |
80 | 96 | } |
81 | 97 |
|
82 | 98 | @Bean |
| 99 | + @Conditional(AnySyncMongoClientAvailable.class) |
83 | 100 | @ConditionalOnMissingBean(MongoDbFactory.class) |
84 | | - public SimpleMongoDbFactory mongoDbFactory(MongoClient mongo) { |
85 | | - String database = this.properties.getMongoClientDatabase(); |
86 | | - return new SimpleMongoDbFactory(mongo, database); |
| 101 | + public MongoDbFactory mongoDbFactory() { |
| 102 | + return this.dbFactoryFactory.getFor(this.properties.getMongoClientDatabase()); |
87 | 103 | } |
88 | 104 |
|
89 | 105 | @Bean |
@@ -166,4 +182,90 @@ public MongoDbFactory withSession(ClientSession session) { |
166 | 182 |
|
167 | 183 | } |
168 | 184 |
|
| 185 | + /** |
| 186 | + * Check if either {@link com.mongodb.MongoClient} or |
| 187 | + * {@link com.mongodb.client.MongoClient} is already defined in the |
| 188 | + * {@link org.springframework.context.ApplicationContext}. |
| 189 | + * |
| 190 | + * @author Christoph Strobl |
| 191 | + * @since 2.1 |
| 192 | + */ |
| 193 | + static class AnySyncMongoClientAvailable extends AnyNestedCondition { |
| 194 | + |
| 195 | + AnySyncMongoClientAvailable() { |
| 196 | + super(ConfigurationPhase.REGISTER_BEAN); |
| 197 | + } |
| 198 | + |
| 199 | + @ConditionalOnBean(com.mongodb.MongoClient.class) |
| 200 | + static class MongoClientPreferred { |
| 201 | + |
| 202 | + } |
| 203 | + |
| 204 | + @ConditionalOnBean(com.mongodb.client.MongoClient.class) |
| 205 | + static class MongoClientClientPreferred { |
| 206 | + |
| 207 | + } |
| 208 | + |
| 209 | + } |
| 210 | + |
| 211 | + /** |
| 212 | + * Encapsulation of {@link MongoDbFactory} creation depending on available beans |
| 213 | + * {@link com.mongodb.MongoClient} or {@link com.mongodb.client.MongoClient} expressed |
| 214 | + * via the given {@link ObjectProvider ObjectProviders}. Prefers the first available |
| 215 | + * MongoDB client creating a suitable instance of {@link MongoDbFactory} for it. |
| 216 | + * |
| 217 | + * @author Christoph Strobl |
| 218 | + * @since 2.1 |
| 219 | + */ |
| 220 | + static class MongoDbFactoryFactory { |
| 221 | + |
| 222 | + private final List<ObjectProvider<?>> clientProviders; |
| 223 | + |
| 224 | + /** |
| 225 | + * Create new instance of {@link MongoDbFactoryFactory}. |
| 226 | + * @param clientProviders order matters here, as we choose the first available |
| 227 | + * one. |
| 228 | + */ |
| 229 | + MongoDbFactoryFactory(ObjectProvider<?>... clientProviders) { |
| 230 | + this.clientProviders = Arrays.asList(clientProviders); |
| 231 | + } |
| 232 | + |
| 233 | + /** |
| 234 | + * Get the {@link MongoDbFactory} suitable for the first available MongoDB client. |
| 235 | + * @param database the name of the default database to return on |
| 236 | + * {@link MongoDbFactory#getDb()}. |
| 237 | + * @return new instance of {@link MongoDbFactory} suitable for the first available |
| 238 | + * MongoDB client. |
| 239 | + */ |
| 240 | + MongoDbFactory getFor(String database) { |
| 241 | + |
| 242 | + Object client = findAvailableClientProvider(); |
| 243 | + |
| 244 | + if (client instanceof MongoClient) { |
| 245 | + return new SimpleMongoDbFactory(MongoClient.class.cast(client), database); |
| 246 | + } |
| 247 | + |
| 248 | + if (client instanceof com.mongodb.client.MongoClient) { |
| 249 | + return new SimpleMongoClientDbFactory( |
| 250 | + com.mongodb.client.MongoClient.class.cast(client), database); |
| 251 | + } |
| 252 | + |
| 253 | + return null; |
| 254 | + } |
| 255 | + |
| 256 | + private Object findAvailableClientProvider() { |
| 257 | + |
| 258 | + for (ObjectProvider<?> provider : this.clientProviders) { |
| 259 | + Object client = provider.getIfAvailable(); |
| 260 | + if (client != null) { |
| 261 | + return client; |
| 262 | + } |
| 263 | + } |
| 264 | + |
| 265 | + throw new IllegalStateException( |
| 266 | + "Expected to find at least one MongoDB client."); |
| 267 | + } |
| 268 | + |
| 269 | + } |
| 270 | + |
169 | 271 | } |
0 commit comments