首先看我们主程序,用到的注解是 @SpringBootApplication来告诉spring Boot这是一个springBoot 项目的启动位置。
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
其实SpringBootApplication 注解是一个组合注解,源码如下,最主要的是两个配置@SpringBootConfiguration ,@EnableAutoConfiguration ,下面具体来分析
@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
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
1.@SpringBootConfiguration
查看@SpringBootConfiguration源码,其实它也就是@Configuration注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Configuration,它就是 JavaConfig 形式的 SpringIOC 容器的配置类,也是 SpringBoot 推荐使用配置形式,所以主程序类标注了 @SpringBootConfiguration 注解,其本身也就是一个配置类@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)。
2. @EnableAutoConfiguration
关于SpringBoot的自动配置原理,还是由@EnableAutoConfigration注解提供,以下是它的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
2.1 @AutoConfigurationPackage
这个注解的主要功能是自动配置包,它会获取主程序类所在的包路径,并将包路径以及子包下的所有组件注册到SpringIoc容器中。
2.2 @Import({AutoConfigurationImportSelector.class})
@EnableAutoConfiguration 的关键功能也是这个 @Import 导入的配置功能,使用
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader())
下的
classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
来扫描META-INF/spring.factories 文件下的jar包,在spring-boot-autoconfigure:2.1.4.RELEASE.jar包下的META-INF下正好有个spring.factories文件:
打开 spring.factories 文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration 指定的自动配置类:
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.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
每一个 xxxAutoConfiguration 类都是容器中的一个组件,都加入到容器中,用它们来做自动配置。
2.3 自动配置分析
每一个 xxxAutoConfiguration都是容器中的一个组件,来做自动配置,下面以RabbitAutoConfiguration为例进行分析,看具体是如何自动配置的,下面是自动配置类RabbitAutoConfiguration的源码。在这个源码上我们可以看到@EnableConfigurationProperties({RabbitProperties.class}),开启属性自动配置
@Configuration
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties({RabbitProperties.class})
@Import({RabbitAnnotationDrivenConfiguration.class})
public class RabbitAutoConfiguration {
public RabbitAutoConfiguration() {
}
@Configuration
@ConditionalOnClass({RabbitMessagingTemplate.class})
@ConditionalOnMissingBean({RabbitMessagingTemplate.class})
@Import({RabbitAutoConfiguration.RabbitTemplateConfiguration.class})
protected static class MessagingTemplateConfiguration {
protected MessagingTemplateConfiguration() {
}
@Bean
@ConditionalOnSingleCandidate(RabbitTemplate.class)
public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
return new RabbitMessagingTemplate(rabbitTemplate);
}
}
}
在RabbitProperties.class中,通过@ConfigurationProperties(prefix = “spring.rabbitmq”)指定前缀是 spring.rabbitmq,在配置文件中的spring.rabbitmq中的属性和RabbitProperties中的属性一一对应,没有配置spring.rabbitmq用默认值。
@ConfigurationProperties(
prefix = "spring.rabbitmq"
)
public class RabbitProperties {
private String host = "localhost";
private int port = 5672;
private String username = "guest";
private String password = "guest";
private final RabbitProperties.Ssl ssl = new RabbitProperties.Ssl();
private String virtualHost;
private String addresses;
@DurationUnit(ChronoUnit.SECONDS)
private Duration requestedHeartbeat;
private boolean publisherConfirms;
private boolean publisherReturns;
private Duration connectionTimeout;
private final RabbitProperties.Cache cache = new RabbitProperties.Cache();
private final RabbitProperties.Listener listener = new RabbitProperties.Listener();
private final RabbitProperties.Template template = new RabbitProperties.Template();
private List<RabbitProperties.Address> parsedAddresses;
public RabbitProperties() {
}
public String getHost() {
return this.host;
}
public String determineHost() {
return CollectionUtils.isEmpty(this.parsedAddresses)?this.getHost():((RabbitProperties.Address)this.parsedAddresses.get(0)).host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return this.port;
}
...
总结:
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @ConfigurationProperties 等几个注解来进行自动配置完成的。
@EnableAutoConfiguration 开启自动配置,主要作用就是调用 Spring-Core 包里的 loadFactoryNames(),将 autoconfig 包里的已经写好的自动配置生成组件加载进IOC容器。
@Conditional 条件注解,通过判断类路径下有没有相应配置的 jar 包来确定是否加载和自动配置这个类。
@EnableConfigurationProperties 的作用就是,给自动配置提供具体的配置参数,只需要写在 application.properties 中,就可以通过映射写入配置类的 POJO 属性中