自动配置原理
了解springboot的自动配置原理首先要理解springboot的属性注入一级@Import注解。
1.springboot属性注入(这里以注入DruidDataSource为例)
1).首先在application.yml中声明相关属性
application.yml
mysql:
driver: com.mysql.jdbc.Driver
username: 4444
password: 3333
url: jdbc:mysql://localhost:3306/test
server:
port: 8989
2).创建属性类并对属性进行注入
//属性类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "mysql") //读取application.yml的属性,并且为当前属性类添加前缀
public class MySqlProperties {
//属性
private String driver;
private String url;
private String username;
private String password;
}
3).创建配置类引入属性类
//配置类
@Configuration
@EnableConfigurationProperties(MySqlProperties.class)//获取配置文件类
public class MySqlConfigration {
//依赖注入
@Autowired
private MySqlProperties mySqlProperties;
@Bean
//把DruidSource交给工厂管理
public DruidDataSource druidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername(mySqlProperties.getUsername());
dataSource.setPassword(mySqlProperties.getPassword());
dataSource.setDriverClassName(mySqlProperties.getDriver());
dataSource.setUrl(mySqlProperties.getUrl());
return dataSource;
}
4).配置文件提示的jar
<!--提示自定义配置文件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
2.@Import
@Import 也可以将组件交由工厂管理 注意:使用@Import注解交由工厂管理的对象名称为全限定名.
第一种使用方式 @Import(value = {Black.class,Pink.class})
第二种使用方式 实现ImportSelector接口和其中方法
springboot用到了第二种方式
实现ImportSelector接口和其中方法
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 逻辑代码
String[] strs={"com.baizhi.conf.Blue","com.baizhi.conf.Red"};
return strs;
}
3.@EnableAutoConfiguration
@EnableAutoConfiguration=@AutoConfigurationPackage+
@Import(EnableAutoConfigurationImportSelector.class) 注解 @AutoConfigurationPackage
//作用就是帮你找到入口类
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@Import(EnableAutoConfigurationImportSelector.class)
//作用就是往容器种添加组件,添加一个全限定名数组.
通过selectImports()方法获取到类的全限定名,以数组形式返回,然后加入到spring的容器中.
//EnableAutoConfigurationImportSelector的父类中
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
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);
}
}
加载类路径下的META-info/spring.factorys从而获取到相关的自动配置类信息
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
//从类路径下获取所有的类对象"META-INF/spring.factories"
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
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;
}
以org.springframework.boot.autoconfigure.EnableAutoConfiguration为键进行取值,获取到相关的自动配置类信息
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
自动配置类是springboot默认提供的自动配置.
每个xxxConfiguration自动配置类在该类中已经预先配置了相关的一些组件,比如视图解析器,但是默认的视图解析器 没有属性值,如果想设置属性值则需通过配置文件进行属性注入方可完成自动配置,这就回到了springboot的属性注入。
而属性配置类一般一properties结尾,每一个自动配置类都会有一个对应的properties。