9.springboot自动配置源码
springboot自动加载的源码解析:
1.springboot的启动类代码如下:
//使用@SpringBootApplication标签标明当前类是springboot的启动类
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
System.out.println("启动springboot项目...");
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
System.out.println("启动成功!");
}
}
2.仔细研究@SpringBootApplication注解:
...
1.@SpringBootConfiguration
2.@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
//该属性可以设置扫描哪个包:例如@SpringBootApplication(scanBasePackages = "cn.com")
String[] scanBasePackages() default {};
}
3.详解1.@SpringBootConfiguration注解:发现其底层也是@Configuration注解,该注解的作用:告诉springboot当前是配置类,可以配合@bean往容器中加载组件
...
@Configuration
public @interface SpringBootConfiguration {
...
}
例如直接在启动类中使用@bean注册组件:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
System.out.println("启动springboot项目...");
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
System.out.println("启动成功!");
}
//此方法是可行的,但是一般是使用专门的配置类进行注册
@Bean
public Car getCar() {
System.out.println("car的创建方法!");
return new Car("宝马", "14万");
}
}
4.详解2注解:@EnableAutoConfiguration自动配置,这是springboot的核心:
4.1.@EnableAutoConfiguration源码
....
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
...
}
4.1.2研究其下面注解:@AutoConfigurationPackage的内容
//往容器中导入Registrar类
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
...
}
Registrar类的详情如下:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
//注册组件
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
}
4.1.3 @Import({AutoConfigurationImportSelector.class})代码研究(自动导入各种选择器)
AutoConfigurationImportSelector类代码:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
...
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
...
}
下续代码:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
...
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
...
}
下续代码:
最终发现:所有的选择器导入的bean都在spring-boot-autoconfigure.jar/META-INF/spring.factories中配置:约有127项
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
按需开启自动配置项:
虽然127个场景所有的自动配置会在springboot启动时全部加载,
最终会进行按需配置,容器中不会存在127个所有的组件,会按需配置:
例子:
例如aop类中:如果项目中有Advice.class这个类,会进行aop bean的注册,但是项目并没有导入Advice的包,自然不会有该类,也不会配置该场景的启动器
//条件选择器:当容器中有这个类时执行下述方法
@ConditionalOnClass({Advice.class})
static class AspectJAutoProxyingConfiguration {
}
例如:amqp类中:
//条件选择器:当容器中存在RabbitTemplate这个类时,会执行下述方法
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties({RabbitProperties.class})
@Import({RabbitAnnotationDrivenConfiguration.class})
public class RabbitAutoConfiguration {
}
注意,注意,注意.....
自动配置的类后面都是XXXAutoConfiguration
每个场景的自动配置类都会将配置关联到一个配置类上(使用@EnableConfigurationProperties(类名)标签去关联springboot的配置文件和这个类)
示例如下:
1.HttpEncodingAutoConfiguration自动配置类
//1.标明当前类是springboot配置类
@Configuration(
proxyBeanMethods = false
)
//2.当前自动配置类和ServerProperties类进行绑定
@EnableConfigurationProperties({ServerProperties.class})
//3.当前应用是传统的servlet的web工程
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//4.项目是否存在CharacterEncodingFilter类
@ConditionalOnClass({CharacterEncodingFilter.class})
//5.条件判断注解:springboot的配置文件中是否存在erver.servlet.encoding为前缀的标签,matchIfMissing=true,即使不存都生效
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
...
}
2.绑定的ServerProperties类代码如下:
@ConfigurationProperties(
//指定配置文件的前缀为:server
prefix = "server",
ignoreUnknownFields = true
)
public class ServerProperties {
...
private Integer port;
private InetAddress address;
...
}
3.在springboot的配置文件中:application.properties中的绑定配置为:
server.port=80080
原理总结:
在绑定的配置类中,各属性有自己默认的值,但当需要更改时,在application.properties中进行配置,@ConfigurationProperties标签
会将其绑定到配置类上的具体属性,达到修改默认值的效果!