前言

  • SpringBoot到底是怎么做到自动配置的?从代码里看项目SpringBoot的项目启动类只有一个注解@SpringBootApplication和一个run方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class SampleTomcatJspApplication extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SampleTomcatJspApplication.class);
}

public static void main(String[] args) throws Exception {
SpringApplication.run(SampleTomcatJspApplication.class, args);
}

}

解析

  • 查看@SpringBootApplication注解
    • @Inherited
      • java.lang.annotation.@Inherited 注解,使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用@Inherited 声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。
    • @SpringBootConfiguration
      • 标记这是一个 Spring Boot 配置类, 它上面继承自 @Configuration 注解,所以两者功能也一致,可以将当前类内声明的一个或多个以 @Bean 注解标记的方法的实例纳入到 Spring 容器中,并且实例名就是方法名。
    • @EnableAutoConfiguration
      • 用于开启自动配置功能,是 spring-boot-autoconfigure 项目最核心的注解
    • @ComponentScan
      • 扫描指定路径下的 Component(@Componment、@Configuration、@Service)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};

@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};

@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
  • 这么多注解我们这里关注@EnableAutoConfiguration注解,可以看到是使用了@Import(EnableAutoConfigurationImportSelector.class)注解,

  • @Import用来导入一个或多个类(会被Spring容器管理),或者配置类(配置类里的@Bean标记的类也会被Spring容器管理),有了这个注解我们可以通过添加注解的形式来注册Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 主要功能自动配置包,它会获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到 Spring IOC 容器中。
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};

/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};

}
  • 查看EnableAutoConfigurationImportSelector.class的继承关系图
  • 上面的图可以看到EnableAutoConfigurationImportSelector类是实现了ImportSelectors接口

    • 实现了ImportSelectors接口的类通常与常规的@Import注解作用相同,然而,它也可能被延迟处理,直到所有被@Configuration标记的类处理完之后采取处理

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public interface ImportSelector {

      /**
      * Select and return the names of which class(es) should be imported based on
      * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
      */
      String[] selectImports(AnnotationMetadata importingClassMetadata);

      }
    • ImportSelector接口的selectImports返回的数组(类的全类名)都会被注册到Spring容器中,所以可以通过这个方法来自定义注册哪些bean

    • 我们来看它是实现这个接口的,可以看到主体逻辑是调用getCandidateConfigurations(annotationMetadata, attributes);获取了list,然后进行去重、排序、筛选排除

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      @Override
      public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
      }
      try {
      AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
      .loadMetadata(this.beanClassLoader);
      AnnotationAttributes attributes = getAttributes(annotationMetadata);
      // 获取META-INF/spring.factories配置的类名
      List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
      // 去重
      configurations = removeDuplicates(configurations);
      // 排序
      configurations = sort(configurations, autoConfigurationMetadata);
      // 筛选排除
      Set<String> exclusions = getExclusions(annotationMetadata, attributes);
      checkExcludedClasses(configurations, exclusions);
      configurations.removeAll(exclusions);
      configurations = filter(configurations, autoConfigurationMetadata);
      fireAutoConfigurationImportEvents(configurations, exclusions);
      return configurations.toArray(new String[configurations.size()]);
      }
      catch (IOException ex) {
      throw new IllegalStateException(ex);
      }
      }
    • 进入getCandidateConfigurations(annotationMetadata, attributes)方法,从下面的方法可以看到是读取了META-INF/spring.factories的配置,这个文件配置了哪些类需要被注册为Bean

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      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<?> factoryClass, ClassLoader classLoader) {
      String factoryClassName = factoryClass.getName();

      try {
      Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
      ArrayList result = new ArrayList();

      while(urls.hasMoreElements()) {
      URL url = (URL)urls.nextElement();
      Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
      String factoryClassNames = properties.getProperty(factoryClassName);
      result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
      }

      return result;
      } catch (IOException var8) {
      throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
      }
      }
    • 查看spring-boot-autoconfigure模块的META-INF/spring.factories文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      # Initializers
      org.springframework.context.ApplicationContextInitializer=\
      org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
      org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

      # Application Listeners
      org.springframework.context.ApplicationListener=\
      org.springframework.boot.autoconfigure.BackgroundPreinitializer

      # Auto Configuration Import Listeners
      org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
      org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

      # Auto Configuration Import Filters
      org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
      org.springframework.boot.autoconfigure.condition.OnClassCondition

      # Auto Configure
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
      org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
      org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
      org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
      org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
      org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
      org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
      org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
      org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
      org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
      org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
      org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
      org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
      org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
      org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
      org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
      org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
      org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
      org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
      org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
      org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
      org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
      org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
      org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
      org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
      org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
      org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
      org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
      org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
      org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
      org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
      org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
      org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
      org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
      org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
      org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
      org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
      org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
      org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
      org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
      org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
      org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
      org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
      org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
      org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
      org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
      org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
      org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
      org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
      org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
      org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
      org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
      org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
      org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
      org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
      org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
      org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
      org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
      org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
      org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
      org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
      org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
      org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
      org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
      org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

      # Failure analyzers
      org.springframework.boot.diagnostics.FailureAnalyzer=\
      org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
      org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
      org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer

      # Template availability providers
      org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
      org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
      org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
      org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
      org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
      org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider
  • 获取到了哪些Bean需要自动配置,我们来看下是哪里调用了,下图是这个方法的调用链

  • 由上面的调用链可以看到容器执行了refresh()时触发的,这个方法在之前Spring系列有过介绍,现在来回顾一下

    • 进入refresh()方法,可以看到是执行了invokeBeanFactoryPostProcessors(beanFactory)方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      @Override
      public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      // 准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      // 初始化BeanFactory,并进行XML文件读取,这一步之后ClassPathXmlApplicationContext实际上就已经包含了BeanFactory所提供的功能
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      // 进入prepareBeanFactory前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开
      // 对BeanFactory进行各种功能组件填充 @Qualifier @Autowired这两注解功能组件就是在这步骤中增加的支持
      prepareBeanFactory(beanFactory);

      try {
      // Allows post-processing of the bean factory in context subclasses.
      // 子类覆盖方法做额外的处理
      postProcessBeanFactory(beanFactory);


      // Invoke factory processors registered as beans in the context.
      // 调用工厂后处理器 根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的bean,
      // 并调用其postProcessBeanFactory接口方法
      invokeBeanFactoryPostProcessors(beanFactory);
      ...
    • 可以看到是执行了工厂后处理器,根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的bean,查看invokeBeanDefinitionRegistryPostProcessors()方法是执行了BeanDefinitionRegistryPostProcessor接口postProcessBeanDefinitionRegistry(registry)方法

      1
      2
      3
      4
      5
      6
      7
      private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

      for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
      postProcessor.postProcessBeanDefinitionRegistry(registry);
      }
      }
    • BeanDefinitionRegistryPostProcessor接口继承了BeanFactoryPostProcessor接口,这里是执行实现了BeanDefinitionRegistryPostProcessor接口BeanpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,用于注册bean

      其他

  • 使用@Configuration注解的类MyConfig与启动类Application如果不在同一包下,才需要配置spring.factories

AopAutoConfiguration 自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
public static class JdkDynamicAutoProxyConfiguration {

}

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {

}

}

CacheAutoConfiguration 自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
@Configuration
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
public class CacheAutoConfiguration {

static final String VALIDATOR_BEAN_NAME = "cacheAutoConfigurationValidator";

@Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(
ObjectProvider<List<CacheManagerCustomizer<?>>> customizers) {
return new CacheManagerCustomizers(customizers.getIfAvailable());
}

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static CacheManagerValidatorPostProcessor cacheAutoConfigurationValidatorPostProcessor() {
return new CacheManagerValidatorPostProcessor();
}

@Bean(name = VALIDATOR_BEAN_NAME)
public CacheManagerValidator cacheAutoConfigurationValidator() {
return new CacheManagerValidator();
}

@Configuration
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
protected static class CacheManagerJpaDependencyConfiguration
extends EntityManagerFactoryDependsOnPostProcessor {

public CacheManagerJpaDependencyConfiguration() {
super("cacheManager");
}

}

/**
* {@link BeanFactoryPostProcessor} to ensure that the {@link CacheManagerValidator}
* is triggered before {@link CacheAspectSupport} but without causing early
* instantiation.
*/
static class CacheManagerValidatorPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
for (String name : beanFactory.getBeanNamesForType(CacheAspectSupport.class,
false, false)) {
BeanDefinition definition = beanFactory.getBeanDefinition(name);
definition.setDependsOn(
append(definition.getDependsOn(), VALIDATOR_BEAN_NAME));
}
}

private String[] append(String[] array, String value) {
String[] result = new String[array == null ? 1 : array.length + 1];
if (array != null) {
System.arraycopy(array, 0, result, 0, array.length);
}
result[result.length - 1] = value;
return result;
}

}

/**
* Bean used to validate that a CacheManager exists and provide a more meaningful
* exception.
*/
static class CacheManagerValidator {

@Autowired
private CacheProperties cacheProperties;

@Autowired(required = false)
private CacheManager cacheManager;

@PostConstruct
public void checkHasCacheManager() {
Assert.notNull(this.cacheManager,
"No cache manager could "
+ "be auto-configured, check your configuration (caching "
+ "type is '" + this.cacheProperties.getType() + "')");
}

}

/**
* {@link ImportSelector} to add {@link CacheType} configuration classes.
*/
static class CacheConfigurationImportSelector implements ImportSelector {

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}

}

}

总结

  • Spring Boot实现自动配置是通过@EnableAutoConfiguration来实现的
  • Spring Boot 在启动时扫描项目所依赖的 jar 包,寻找包含spring.factories 文件的 jar 包,根据 spring.factories 配置加载 AutoConfigure 类。
  • 在自动配置类AutoConfigure 类下然后将满足条件(@ConditionalOnXxx)的@Bean放入到Spring容器中Spring Context

参考