Spring Boot Mongodb

时间:2020-12-11 04:18:28

Spring注解学习,有助于更好的理解下面代码:

  • @ConditionOnClass表明该@Configuration仅仅在一定条件下才会被加载,这里的条件是Mongo.class位于类路径上
  • @EnableConfigurationProperties将Spring Boot的配置文件(application.properties)中的spring.data.mongodb.*属性映射为MongoProperties并注入到MongoAutoConfiguration中。
  • @ConditionalOnMissingBean说明Spring Boot仅仅在当前上下文中不存在Mongo对象时,才会实例化一个Bean。这个逻辑也体现了Spring
    Boot的另外一个特性——自定义的Bean优先于框架的默认配置,我们如果显式的在业务代码中定义了一个Mongo对象,那么Spring Boot就不再创建。

一、先看看spring boot mongo部分源码片段

/*
* Copyright 2012-2015 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.boot.autoconfigure.mongo; import java.net.UnknownHostException; import javax.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions; /**
* {@link EnableAutoConfiguration Auto-configuration} for Mongo.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Phillip Webb
*/
@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration { @Autowired
private MongoProperties properties; @Autowired(required = false)
private MongoClientOptions options; @Autowired
private Environment environment; private MongoClient mongo; @PreDestroy
public void close() {
if (this.mongo != null) {
this.mongo.close();
}
} @Bean
@ConditionalOnMissingBean
public MongoClient mongo() throws UnknownHostException {
this.mongo = this.properties.createMongoClient(this.options, this.environment);
return this.mongo;
} }
/*
* Copyright 2012-2015 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.boot.autoconfigure.mongo; import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoClient; /**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's mongo support.
* <p>
* Registers a {@link MongoTemplate} and {@link GridFsTemplate} beans if no other beans of
* the same type are configured.
* <P>
* Honors the {@literal spring.data.mongodb.database} property if set, otherwise connects
* to the {@literal test} database.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Josh Long
* @author Phillip Webb
* @author Eddú Meléndez
* @since 1.1.0
*/
@Configuration
@ConditionalOnClass({ Mongo.class, MongoTemplate.class })
@EnableConfigurationProperties(MongoProperties.class)
@AutoConfigureAfter(MongoAutoConfiguration.class)
public class MongoDataAutoConfiguration implements BeanClassLoaderAware { @Autowired
private MongoProperties properties; @Autowired
private Environment environment; @Autowired
private ResourceLoader resourceLoader; private ClassLoader classLoader; @Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
} @Bean
@ConditionalOnMissingBean(MongoDbFactory.class)
public SimpleMongoDbFactory mongoDbFactory(MongoClient mongo) throws Exception {
String database = this.properties.getMongoClientDatabase();
return new SimpleMongoDbFactory(mongo, database);
} @Bean
@ConditionalOnMissingBean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory,
MongoConverter converter) throws UnknownHostException {
return new MongoTemplate(mongoDbFactory, converter);
} @Bean
@ConditionalOnMissingBean(MongoConverter.class)
public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory,
MongoMappingContext context, BeanFactory beanFactory) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver,
context);
try {
mappingConverter.setCustomConversions(beanFactory
.getBean(CustomConversions.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore
}
return mappingConverter;
} @Bean
@ConditionalOnMissingBean
public MongoMappingContext mongoMappingContext(BeanFactory beanFactory)
throws ClassNotFoundException {
MongoMappingContext context = new MongoMappingContext();
context.setInitialEntitySet(getInitialEntitySet(beanFactory));
Class<? extends FieldNamingStrategy> strategyClass = this.properties
.getFieldNamingStrategy();
if (strategyClass != null) {
context.setFieldNamingStrategy(BeanUtils.instantiate(strategyClass));
}
return context;
} private Set<Class<?>> getInitialEntitySet(BeanFactory beanFactory)
throws ClassNotFoundException {
Set<Class<?>> entitySet = new HashSet<Class<?>>();
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
false);
scanner.setEnvironment(this.environment);
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(Document.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (String basePackage : getMappingBasePackages(beanFactory)) {
if (StringUtils.hasText(basePackage)) {
for (BeanDefinition candidate : scanner
.findCandidateComponents(basePackage)) {
entitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
this.classLoader));
}
}
}
return entitySet;
} private static Collection<String> getMappingBasePackages(BeanFactory beanFactory) {
try {
return AutoConfigurationPackages.get(beanFactory);
}
catch (IllegalStateException ex) {
// no auto-configuration package registered yet
return Collections.emptyList();
}
} @Bean
@ConditionalOnMissingBean
public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory,
MongoTemplate mongoTemplate) {
return new GridFsTemplate(new GridFsMongoDbFactory(mongoDbFactory,
this.properties), mongoTemplate.getConverter());
} /**
* {@link MongoDbFactory} decorator to respect
* {@link MongoProperties#getGridFsDatabase()} if set.
*/
private static class GridFsMongoDbFactory implements MongoDbFactory { private final MongoDbFactory mongoDbFactory; private final MongoProperties properties; public GridFsMongoDbFactory(MongoDbFactory mongoDbFactory,
MongoProperties properties) {
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null");
Assert.notNull(properties, "Properties must not be null");
this.mongoDbFactory = mongoDbFactory;
this.properties = properties;
} @Override
public DB getDb() throws DataAccessException {
String gridFsDatabase = this.properties.getGridFsDatabase();
if (StringUtils.hasText(gridFsDatabase)) {
return this.mongoDbFactory.getDb(gridFsDatabase);
}
return this.mongoDbFactory.getDb();
} @Override
public DB getDb(String dbName) throws DataAccessException {
return this.mongoDbFactory.getDb(dbName);
} @Override
public PersistenceExceptionTranslator getExceptionTranslator() {
return this.mongoDbFactory.getExceptionTranslator();
} } }
/*
* Copyright 2012-2015 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.boot.autoconfigure.mongo; import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.data.mapping.model.FieldNamingStrategy; import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress; /**
* Configuration properties for Mongo.
*
* @author Dave Syer
* @author Phillip Webb
* @author Josh Long
* @author Andy Wilkinson
* @author Eddú Meléndez
*/
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties { /**
* Default port used when the configured port is {@code null}.
*/
public static final int DEFAULT_PORT = 27017; /**
* Mongo server host.
*/
private String host; /**
* Mongo server port.
*/
private Integer port = null; /**
* Mongo database URI. When set, host and port are ignored.
*/
private String uri = "mongodb://localhost/test"; /**
* Database name.
*/
private String database; /**
* Authentication database name.
*/
private String authenticationDatabase; /**
* GridFS database name.
*/
private String gridFsDatabase; /**
* Login user of the mongo server.
*/
private String username; /**
* Login password of the mongo server.
*/
private char[] password; /**
* Fully qualified name of the FieldNamingStrategy to use.
*/
private Class<? extends FieldNamingStrategy> fieldNamingStrategy; public String getHost() {
return this.host;
} public void setHost(String host) {
this.host = host;
} public String getDatabase() {
return this.database;
} public void setDatabase(String database) {
this.database = database;
} public String getAuthenticationDatabase() {
return this.authenticationDatabase;
} public void setAuthenticationDatabase(String authenticationDatabase) {
this.authenticationDatabase = authenticationDatabase;
} public String getUsername() {
return this.username;
} public void setUsername(String username) {
this.username = username;
} public char[] getPassword() {
return this.password;
} public void setPassword(char[] password) {
this.password = password;
} public Class<? extends FieldNamingStrategy> getFieldNamingStrategy() {
return this.fieldNamingStrategy;
} public void setFieldNamingStrategy(
Class<? extends FieldNamingStrategy> fieldNamingStrategy) {
this.fieldNamingStrategy = fieldNamingStrategy;
} public void clearPassword() {
if (this.password == null) {
return;
}
for (int i = 0; i < this.password.length; i++) {
this.password[i] = 0;
}
} public String getUri() {
return this.uri;
} public void setUri(String uri) {
this.uri = uri;
} public Integer getPort() {
return this.port;
} public void setPort(Integer port) {
this.port = port;
} public String getGridFsDatabase() {
return this.gridFsDatabase;
} public void setGridFsDatabase(String gridFsDatabase) {
this.gridFsDatabase = gridFsDatabase;
} public String getMongoClientDatabase() {
if (this.database != null) {
return this.database;
}
return new MongoClientURI(this.uri).getDatabase();
} /**
* Creates a {@link MongoClient} using the given {@code options}
*
* @param options the options
* @return the Mongo client
* @throws UnknownHostException if the configured host is unknown
* @deprecated Since 1.3.0 in favour of
* {@link #createMongoClient(MongoClientOptions, Environment)}
*/
@Deprecated
public MongoClient createMongoClient(MongoClientOptions options)
throws UnknownHostException {
return this.createMongoClient(options, null);
} /**
* Creates a {@link MongoClient} using the given {@code options} and
* {@code environment}. If the configured port is zero, the value of the
* {@code local.mongo.port} property retrieved from the {@code environment} is used
* to configure the client.
*
* @param options the options
* @param environment the environment
* @return the Mongo client
* @throws UnknownHostException if the configured host is unknown
*/
public MongoClient createMongoClient(MongoClientOptions options,
Environment environment) throws UnknownHostException {
try {
if (hasCustomAddress() || hasCustomCredentials()) {
if (options == null) {
options = MongoClientOptions.builder().build();
}
List<MongoCredential> credentials = null;
if (hasCustomCredentials()) {
String database = this.authenticationDatabase == null ? getMongoClientDatabase()
: this.authenticationDatabase;
credentials = Arrays.asList(MongoCredential.createMongoCRCredential(
this.username, database, this.password));
}
String host = this.host == null ? "localhost" : this.host;
int port = determinePort(environment);
return new MongoClient(Arrays.asList(new ServerAddress(host, port)),
credentials, options);
}
// The options and credentials are in the URI
return new MongoClient(new MongoClientURI(this.uri, builder(options)));
}
finally {
clearPassword();
}
} private boolean hasCustomAddress() {
return this.host != null || this.port != null;
} private boolean hasCustomCredentials() {
return this.username != null && this.password != null;
} private int determinePort(Environment environment) {
if (this.port == null) {
return DEFAULT_PORT;
}
if (this.port == 0) {
if (environment != null) {
String localPort = environment.getProperty("local.mongo.port");
if (localPort != null) {
return Integer.valueOf(localPort);
}
}
throw new IllegalStateException(
"spring.data.mongodb.port=0 and no local mongo port configuration "
+ "is available");
}
return this.port;
} private Builder builder(MongoClientOptions options) {
Builder builder = MongoClientOptions.builder();
if (options != null) {
builder.alwaysUseMBeans(options.isAlwaysUseMBeans());
builder.connectionsPerHost(options.getConnectionsPerHost());
builder.connectTimeout(options.getConnectTimeout());
builder.cursorFinalizerEnabled(options.isCursorFinalizerEnabled());
builder.dbDecoderFactory(options.getDbDecoderFactory());
builder.dbEncoderFactory(options.getDbEncoderFactory());
builder.description(options.getDescription());
builder.maxWaitTime(options.getMaxWaitTime());
builder.readPreference(options.getReadPreference());
builder.socketFactory(options.getSocketFactory());
builder.socketKeepAlive(options.isSocketKeepAlive());
builder.socketTimeout(options.getSocketTimeout());
builder.threadsAllowedToBlockForConnectionMultiplier(options
.getThreadsAllowedToBlockForConnectionMultiplier());
builder.writeConcern(options.getWriteConcern());
}
return builder;
} }

------------------------------------------------------------------------------------------------------------------------------------------------------

以上为spring boot mongo的片段,可以看出spring boot已经配置好了,也就是说springboot启动后@Bean创建的对象可以直接使用@Autowrite直接使用

关注点(spring boot启动会直接读取application.yml或者是application.properties,这里我用的是yml)

@ConfigurationProperties(prefix = "spring.data.mongodb")

public class MongoProperties

启动入口

Applicaiton.java

package com.modou.weixin;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate; /**
* Created by chababa on 15/8/22.
*/
@Configuration
@ComponentScan(basePackages={"com.modou.conf","com.modou.weixin"})
@EnableAutoConfiguration
public class Application implements CommandLineRunner{
@Autowired
MongoTemplate template; public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} @Override
public void run(String... args) throws Exception {
System.err.println(template != null);
}
}

注入MongoTemplate结果

Spring Boot Mongodb

# SPRING PROFILES
spring:
# HTTP ENCODING
http:
encoding.charset: UTF-8
encoding.enable: true
encoding.force: true
data:
mongodb:
host: 127.0.0.1
port: 27017
username:
password:
database: xx
authenticationDatabase: