Spring约定的目录
DataSource自动配置过程
API 是sun公司定义的规则META-INF/servises/xx spring同样支持自动配置,但规则略有不同 META-INF/spring.factories – EnableAutoConfiguration
META- INF/ spring. factories -> EnableAutoConfiguration -> org. springframework. boot. autoconfigure. jdbc. DataSourceAutoConfiguration, \
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@Configuration ( proxyBeanMethods = false )
@ConditionalOnClass ( { DataSource . class , EmbeddedDatabaseType . class } )
@ConditionalOnMissingBean ( type = "io.r2dbc.spi.ConnectionFactory" )
@AutoConfigureBefore ( SqlInitializationAutoConfiguration . class )
@EnableConfigurationProperties ( DataSourceProperties . class )
@Import ( { DataSourcePoolMetadataProvidersConfiguration . class ,
DataSourceInitializationConfiguration. InitializationSpecificCredentialsDataSourceInitializationConfiguration . class ,
DataSourceInitializationConfiguration. SharedCredentialsDataSourceInitializationConfiguration . class } )
public class DataSourceAutoConfiguration {
@Configuration ( proxyBeanMethods = false )
@Conditional ( EmbeddedDatabaseCondition . class )
@ConditionalOnMissingBean ( { DataSource . class , XADataSource . class } )
@Import ( EmbeddedDataSourceConfiguration . class )
protected static class EmbeddedDatabaseConfiguration { }
@Configuration ( proxyBeanMethods = false )
@Conditional ( PooledDataSourceCondition . class )
@ConditionalOnMissingBean ( { DataSource . class , XADataSource . class } )
@Import ( { DataSourceConfiguration. Hikari . class , DataSourceConfiguration. Tomcat . class ,
DataSourceConfiguration. Dbcp2 . class , DataSourceConfiguration. OracleUcp . class ,
DataSourceConfiguration. Generic . class , DataSourceJmxConfiguration . class } )
protected static class PooledDataSourceConfiguration { }
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@ConfigurationProperties ( prefix = "spring.datasource" )
public class DataSourceProperties implements BeanClassLoaderAware , InitializingBean { . . . . . . . . . . . . . . . . . . . . . }
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@org.springframework.context.annotation.Configuration ( proxyBeanMethods = false )
@org.springframework.context.annotation.Conditional ( DifferentCredentialsCondition . class )
@org.springframework.context.annotation.Import ( DatabaseInitializationDependencyConfigurer . class )
@ConditionalOnSingleCandidate ( DataSource . class )
@ConditionalOnMissingBean ( DataSourceScriptDatabaseInitializer . class )
static class InitializationSpecificCredentialsDataSourceInitializationConfiguration {
@Bean
SqlDataSourceScriptDatabaseInitializer ddlOnlyScriptDataSourceInitializer ( ObjectProvider < DataSource > dataSource,
DataSourceProperties properties) {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings ( ) ;
settings. setSchemaLocations ( scriptLocations ( properties. getSchema ( ) , "schema" , properties. getPlatform ( ) ) ) ;
settings. setContinueOnError ( properties. isContinueOnError ( ) ) ;
settings. setSeparator ( properties. getSeparator ( ) ) ;
settings. setEncoding ( properties. getSqlScriptEncoding ( ) ) ;
settings. setMode ( mapMode ( properties. getInitializationMode ( ) ) ) ;
DataSource initializationDataSource = determineDataSource ( dataSource:: getObject ,
properties. getSchemaUsername ( ) , properties. getSchemaPassword ( ) ) ;
return new SqlDataSourceScriptDatabaseInitializer ( initializationDataSource, settings) ;
}
@Bean
@DependsOn ( "ddlOnlyScriptDataSourceInitializer" )
SqlDataSourceScriptDatabaseInitializer dmlOnlyScriptDataSourceInitializer ( ObjectProvider < DataSource > dataSource,
DataSourceProperties properties) {
DatabaseInitializationSettings settings = new DatabaseInitializationSettings ( ) ;
settings. setDataLocations ( scriptLocations ( properties. getData ( ) , "data" , properties. getPlatform ( ) ) ) ;
settings. setContinueOnError ( properties. isContinueOnError ( ) ) ;
settings. setSeparator ( properties. getSeparator ( ) ) ;
settings. setEncoding ( properties. getSqlScriptEncoding ( ) ) ;
settings. setMode ( mapMode ( properties. getInitializationMode ( ) ) ) ;
DataSource initializationDataSource = determineDataSource ( dataSource:: getObject ,
properties. getDataUsername ( ) , properties. getDataPassword ( ) ) ;
return new SqlDataSourceScriptDatabaseInitializer ( initializationDataSource, settings) ;
}
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@Configuration ( proxyBeanMethods = false )
@AutoConfigureAfter ( { R2dbcAutoConfiguration . class , DataSourceAutoConfiguration . class } )
@EnableConfigurationProperties ( SqlInitializationProperties . class )
@Import ( { DatabaseInitializationDependencyConfigurer . class , R2dbcInitializationConfiguration . class ,
DataSourceInitializationConfiguration . class } )
@ConditionalOnProperty ( prefix = "spring.sql.init" , name = "enabled" , matchIfMissing = true )
@Conditional ( SqlInitializationModeCondition . class )
public class SqlInitializationAutoConfiguration {
static class SqlInitializationModeCondition extends NoneNestedConditions {
SqlInitializationModeCondition ( ) {
super ( ConfigurationPhase . PARSE_CONFIGURATION) ;
}
@ConditionalOnProperty ( prefix = "spring.sql.init" , name = "mode" , havingValue = "never" )
static class ModeIsNever {
}
}
}
JdbcTemplate自动配置过程
META- INF/ spring. factories -> EnableAutoConfiguration -> org. springframework. boot. autoconfigure. jdbc. JdbcTemplateAutoConfiguration, \
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
@Configuration ( proxyBeanMethods = false )
@ConditionalOnClass ( { DataSource . class , JdbcTemplate . class } )
@ConditionalOnSingleCandidate ( DataSource . class )
@AutoConfigureAfter ( DataSourceAutoConfiguration . class )
@EnableConfigurationProperties ( JdbcProperties . class )
@Import ( { DatabaseInitializationDependencyConfigurer . class , JdbcTemplateConfiguration . class ,
NamedParameterJdbcTemplateConfiguration . class } )
public class JdbcTemplateAutoConfiguration {
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
配置:
spring:
jdbc:
fetch- size: 5
. . . . . .
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
@ConfigurationProperties ( prefix = "spring.jdbc" )
public class JdbcProperties {
private final Template template = new Template ( ) ;
public Template getTemplate ( ) {
return this . template;
}
public static class Template {
private int fetchSize = - 1 ;
private int maxRows = - 1 ;
@DurationUnit ( ChronoUnit . SECONDS)
private Duration queryTimeout;
public int getFetchSize ( ) {
return this . fetchSize;
}
public void setFetchSize ( int fetchSize) {
this . fetchSize = fetchSize;
}
public int getMaxRows ( ) {
return this . maxRows;
}
public void setMaxRows ( int maxRows) {
this . maxRows = maxRows;
}
public Duration getQueryTimeout ( ) {
return this . queryTimeout;
}
public void setQueryTimeout ( Duration queryTimeout) {
this . queryTimeout = queryTimeout;
}
}
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
@Configuration ( proxyBeanMethods = false )
@ConditionalOnMissingBean ( JdbcOperations . class )
class JdbcTemplateConfiguration {
@Bean
@Primary
JdbcTemplate jdbcTemplate ( DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate ( dataSource) ;
JdbcProperties. Template template = properties. getTemplate ( ) ;
jdbcTemplate. setFetchSize ( template. getFetchSize ( ) ) ;
jdbcTemplate. setMaxRows ( template. getMaxRows ( ) ) ;
if ( template. getQueryTimeout ( ) != null ) {
jdbcTemplate. setQueryTimeout ( ( int ) template. getQueryTimeout ( ) . getSeconds ( ) ) ;
}
return jdbcTemplate;
}
}
自动配置原理
1.过程
1. 双亲委派加载所有有META- INF/ spring. factories路径的jar,同时解析其中的接口名,以及接口下的实现类
以( 类加载器, Map ( 接口Class , List 实现类) ) 的形式保存到catch 缓存中
2. 通过指定类加载器获取指定接口下所有的实现类,再根据条件注解排除不需要的
2.准备阶段
利用类加载器加载META-INF/spring.factories中配置的接口及类,形成map,并存到缓存cache
SpringFactoriesLoader
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public static List < String > loadFactoryNames ( Class < ? > factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if ( classLoader == null ) {
classLoaderToUse = SpringFactoriesLoader . class . getClassLoader ( ) ;
}
String factoryTypeName = factoryType. getName ( ) ;
return ( List ) loadSpringFactories ( classLoaderToUse) . getOrDefault ( factoryTypeName, Collections . emptyList ( ) ) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
private static Map < String , List < String > > loadSpringFactories ( ClassLoader classLoader) {
Map < String , List < String > > result = ( Map ) cache. get ( classLoader) ;
if ( result != null ) {
return result;
} else {
HashMap result = new HashMap ( ) ;
try {
Enumeration urls = classLoader. getResources ( "META-INF/spring.factories" ) ;
while ( urls. hasMoreElements ( ) ) {
URL url = ( URL) urls. nextElement ( ) ;
UrlResource resource = new UrlResource ( url) ;
Properties properties = PropertiesLoaderUtils . loadProperties ( resource) ;
Iterator var6 = properties. entrySet ( ) . iterator ( ) ;
while ( var6. hasNext ( ) ) {
Entry < ? , ? > entry = ( Entry ) var6. next ( ) ;
String factoryTypeName = ( ( String ) entry. getKey ( ) ) . trim ( ) ;
String [ ] factoryImplementationNames = StringUtils . commaDelimitedListToStringArray ( ( String ) entry. getValue ( ) ) ;
String [ ] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames. length;
for ( int var12 = 0 ; var12 < var11; ++ var12) {
String factoryImplementationName = var10[ var12] ;
( ( List ) result. computeIfAbsent ( factoryTypeName, ( key) -> {
return new ArrayList ( ) ;
} ) ) . add ( factoryImplementationName. trim ( ) ) ;
}
}
}
result. replaceAll ( ( factoryType, implementations) -> {
return ( List ) implementations. stream ( ) . distinct ( ) . collect ( Collectors . collectingAndThen ( Collectors . toList ( ) , Collections :: unmodifiableList ) ) ;
} ) ;
cache. put ( classLoader, result) ;
return result;
} catch ( IOException var14) {
throw new IllegalArgumentException ( "Unable to load factories from location [META-INF/spring.factories]" , var14) ;
}
}
}
3.获取指定接口下所有的实现类,再根据条件注解排除不需要的
@SpringBootApplication -- > @EnableAutoConfiguration -- > AutoConfigurationImportSelector
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public String [ ] selectImports ( AnnotationMetadata annotationMetadata) {
if ( ! isEnabled ( annotationMetadata) ) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry ( annotationMetadata) ;
return StringUtils . toStringArray ( autoConfigurationEntry. getConfigurations ( ) ) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
protected AutoConfigurationEntry getAutoConfigurationEntry ( AnnotationMetadata annotationMetadata) {
if ( ! isEnabled ( annotationMetadata) ) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes ( annotationMetadata) ;
List < String > configurations = getCandidateConfigurations ( annotationMetadata, attributes) ;
configurations = removeDuplicates ( configurations) ;
Set < String > exclusions = getExclusions ( annotationMetadata, attributes) ;
checkExcludedClasses ( configurations, exclusions) ;
configurations. removeAll ( exclusions) ;
configurations = getConfigurationClassFilter ( ) . filter ( configurations) ;
fireAutoConfigurationImportEvents ( configurations, exclusions) ;
return new AutoConfigurationEntry ( configurations, exclusions) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
protected List < String > getCandidateConfigurations ( AnnotationMetadata metadata, AnnotationAttributes attributes) {
List < String > configurations = SpringFactoriesLoader . loadFactoryNames ( getSpringFactoriesLoaderFactoryClass ( ) ,
getBeanClassLoader ( ) ) ;
Assert . notEmpty ( configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct." ) ;
return configurations;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public static List < String > loadFactoryNames ( Class < ? > factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if ( classLoader == null ) {
classLoaderToUse = SpringFactoriesLoader . class . getClassLoader ( ) ;
}
String factoryTypeName = factoryType. getName ( ) ;
return ( List ) loadSpringFactories ( classLoaderToUse) . getOrDefault ( factoryTypeName, Collections . emptyList ( ) ) ;
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
private static Map < String , List < String > > loadSpringFactories ( ClassLoader classLoader) {
Map < String , List < String > > result = ( Map ) cache. get ( classLoader) ;
if ( result != null ) {
return result;
} else {
HashMap result = new HashMap ( ) ;
try {
Enumeration urls = classLoader. getResources ( "META-INF/spring.factories" ) ;
while ( urls. hasMoreElements ( ) ) {
URL url = ( URL) urls. nextElement ( ) ;
UrlResource resource = new UrlResource ( url) ;
Properties properties = PropertiesLoaderUtils . loadProperties ( resource) ;
Iterator var6 = properties. entrySet ( ) . iterator ( ) ;
while ( var6. hasNext ( ) ) {
Entry < ? , ? > entry = ( Entry ) var6. next ( ) ;
String factoryTypeName = ( ( String ) entry. getKey ( ) ) . trim ( ) ;
String [ ] factoryImplementationNames = StringUtils . commaDelimitedListToStringArray ( ( String ) entry. getValue ( ) ) ;
String [ ] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames. length;
for ( int var12 = 0 ; var12 < var11; ++ var12) {
String factoryImplementationName = var10[ var12] ;
( ( List ) result. computeIfAbsent ( factoryTypeName, ( key) -> {
return new ArrayList ( ) ;
} ) ) . add ( factoryImplementationName. trim ( ) ) ;
}
}
}
result. replaceAll ( ( factoryType, implementations) -> {
return ( List ) implementations. stream ( ) . distinct ( ) . collect ( Collectors . collectingAndThen ( Collectors . toList ( ) , Collections :: unmodifiableList ) ) ;
} ) ;
cache. put ( classLoader, result) ;
return result;
} catch ( IOException var14) {
throw new IllegalArgumentException ( "Unable to load factories from location [META-INF/spring.factories]" , var14) ;
}
}
}