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 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: