首先,我们写一个 Pojo 类
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
// get、set方法,以及toString() 要写,此处省略...
}
@component我们知道,是Spring中的注解,用来像容器中注册一个Bean类型
@configurationProperties 则是SpringBoot的注解,那么他有什么用呢,括号内的参数有什么用呢? 不妨我们先测试一下
接下来写 yml配置文件:
person:
age: 23
name: chen
测试:
@Test
void contextLoads() {
System.out.println(person.toString());
}
好了,我们可以看到,我们什么都没用在pojo类中做,只是书写了配置文件,我们的属性值已经导进去了。而这就归功于@configurationProperties,而括号中的 prefix 参数就是对应着yaml文件中的前缀,这样才能绑定成功。
好了,有了前面的铺垫,现在我们可以进入主题,那么SpringBoot到底做了什么,那么多的组件是如何启动成功的呢? 我们从启动类来看
我们点进@SpringBootApplication 注解,看到它的注解组成
第一-第四: Java的四个元注解,不做过多赘述。
我们点进 @SpringBootConfiguration,
可以看到,这个注解本质上是说这个也是一个配置类
进入 @EnableAutoConfiguration
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
这里我们看最后面两个注解:
// 见名知意 获取候选配置,拿到了一个配置的集合
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 点进去
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
提到了一个文件,META-INF/spring.factories,我们全局搜索打开它
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# 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.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# 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.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,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
里面全部都是 XXXAutoConfiguration
我们随便点进去一个
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties({RabbitProperties.class})
@Import({RabbitAnnotationDrivenConfiguration.class})
public class RabbitAutoConfiguration {
public RabbitAutoConfiguration() {
}
......
}
// 可以看到注解里面有一个 EnableConfigurationproperties,见名知意,开启属性自动配置,那么括号里面应该就是配置属性类,点进去
@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 publisherReturns;
private ConfirmType publisherConfirmType;
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() {
}
......
}
到这里我们发现回到了第一部分我们讲解SpringBoot配置注入的地方
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。