springBoot项目自动装配核心注解就是@SpringBootApplication
我们点击@SpringBootApplication这是一个复合注解里面还有三个重要的注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@ComponentScan这个我们都知道是开启包扫描的,注入到IOC容器中(扫描的注解包括@Component} {@Repository}, {@Service}{@Autowired} or { @Controller )
我们重点说一下剩下的两个注解
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
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 {};
}
他的核心类就是AutoConfigurationImportSelector
我们看一下它定义的变量 是不是很熟悉,BeanFactory(Bean工厂),Environment(proerty JVM环境变量)
可以看出,AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。
ImportSelector实现的处理方式通常与常规@Import注释相同,但是,也可以推迟选择导入,直到所有@Configuration类都已处理完毕
这里最重要的方法就是
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//移除掉需要排除的配置
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
我们继续看里面的getCandidateConfigurations方法
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;
}
这里调用 SpringFactoriesLoader.loadFactoryNames方法
使用给定的类加载器从“META-INF/spring.factories”加载给定类型的工厂实现的完全限定类名。
在这里插入图片描述
总结:
1.!isEnabled(annotationMetadata)判断spring.boot.enableautoconfiguration的属性值默认设置为true,可以自己在yml文件里面设置为false
2. getCandidateConfigurations(annotationMetadata, attributes);
扫描获取“META-INF/spring.factories”下要加载的自动配置文件(这里是按需加载) 不懂的可以看下我另一篇文章
配置Spring Boot通过@ConditionalOnProperty来控制Configuration是否生效
3.getExclusions(annotationMetadata, attributes);
获取要排除的配置
@AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
/**
* Base packages that should be registered with {@link AutoConfigurationPackages}.
* <p>
* Use {@link #basePackageClasses} for a type-safe alternative to String-based package
* names.
* @return the back package names
* @since 2.3.0
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages to be
* registered with {@link AutoConfigurationPackages}.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return the base package classes
* @since 2.3.0
*/
Class<?>[] basePackageClasses() default {};
}
我们来看他的核心方法
我们可以看到他实现了ImportBeanDefinitionRegistrar接口
registerBeanDefinitions方法是扫描将@Configuration @Import注解的类注入到IOC容器中
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
这里你们是不是想到了@compentscan注解不是也是用来扫描包的吗为什么还需要@AutoConfigurationPackage呢?
@compentscan和 @AutoConfigurationPackage的区别
1.@compentscan可以扫描除了根包还可以扫描其他的包但是@AutoConfigurationPackage不能
2.@compentscan和 @AutoConfigurationPackage扫描的范围不同
-
@compentscan可以扫描含有{@Component} {@Repository}, {@Service}{@Autowired}{
@Controller ) -
@AutoConfigurationPackage是扫描带有@Configuration @Import注解的类
扩展spring yaml配置文件
以redis为例
@ConfigurationProperties
外部化配置的注释。如果要绑定和验证某些外部属性(例如从.Properties文件),请将其添加到@Configuration类中的类定义或@Bean方法中。 绑定可以通过调用带注释类上的setter来执行,如果使用@ConstructorBinding,则可以通过绑定到构造函数参数来执行。 请注意,与@Value相反,由于属性值是外部化的,所以不会计算SpEL表达式。
spring不会全部装配的原因
就是类似@ConditionalOnClass,@ConditionalOnMissingBean之类的注解,有兴趣的可以自己了解一下,我这里就不详细写了