SpringBoot能实现自动装配的王炸的功能全靠 @EnableAutoConfiguration这个注解。阅读源码之前,我会先介绍重要的Configuratio相关的配置类注注解的用法,后面再介绍这个@EnableAutoConfiguration
配置类注解荟萃
@Configuration
? ? ?这个注解声明了,这个类是配置类,需要扫描类,将Bean注入容器,分为两种模式一种是lite,一种是full,参数为 proxyBeanMethods ,为true加载,为false不加载,对应lite和full
?@ConditionalOnBean(name="xx")
? ? ?这个注解要求只有容器有xx组件才能注入Bean,否则不注入
@ConditionalOnMissingBean(name="xx")
? ? ?这个注解声明了容器是否包含xx Bean,若无就实现注入 xx Bean
@Bean
? 配合前两种使用,声明Bean
@Import({xx.class})
? ?组件工具, 支持注入多个其他组件实例
下面有代码说明
import org.springframework.boot.context.properties.ConfigurationProperties;
//读取配置文件
@ConfigurationProperties("infobind")
public class User {
private String name;
private int age;
private Cat cat;
public User(String lin, String s) {
}
public User(String name, int i) {
this.name=name;
this.age=i;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", cat=" + cat +
'}';
}
public int getAge() {
return age;
}
public User() {
}
public void setAge(int age) {
this.age = age;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
}
public class Cat {
private String name;
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
public Cat(String tom) {
this.name=tom;
}
}
?配置类
//数组形式,可以导入其他的组件,自动创建出组件,返回组件实例
@Import({User.class, Date.class})
//proxyBeanMethods 使spring去检查是组件是否放入容器中
//为true时候将bean加载进入容器 false不加载 简称为full/lite模式
@Configuration(proxyBeanMethods = true)
public class UserConfig {
/**
* bean给组件注册方法,是一致性的/幂等性的,以方法名为组件的id,返回类型和返回名字和组件的
* */
// @ConditionalOnMissingBean(name = "cat")//没有立即注入
// @ConditionalOnBean(name = "cat")//容器中有组件才生效 使用它时候会提示出错 bean不存在 因为无法确定bean的前后加载顺序将导致Bean不存在
@Bean
public User userBean(){
User user = new User("lin",11);
user.setCat(getCat());
return user ;
}
@Bean("cat")
public Cat getCat(){
return new Cat("tom");
}
}
@SpringBootApplication
public class SpringCodeAnalysisApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringCodeAnalysisApplication.class, args);
//读取所有的Bean
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
//Bean在容器内是不变的
Cat cat=run.getBean(Cat.class);
UserConfig userConfig=run.getBean(UserConfig.class);
User user1 = userConfig.userBean();
User user2 = userConfig.userBean();
System.out.println(user1==user2);
//说明User的cat和cat是同一个对象
System.out.println(cat==user2.getCat());
//获取bean=>检查Import是否成功
String[] parmtype= run.getBeanNamesForType(User.class);
for (String s : parmtype) {
System.out.println(s);
}
Date date = run.getBean(Date.class);
System.out.println(date);
//测试是否注入cat bean
boolean flag = run.containsBean("cat");
System.out.println(flag);
}
}

正式开始
回到前面,我们打开源码可以看到
这个注解的底层源码是这样的,上面有两个实现的关键的注解,一个是@AutoConfigurationPackage,@一个是AutoConfigurationImportSelector.第一个

?这个@AutoConfigurationPackage 是方法是把批量扫描包。Spring底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class 将主配置类(@SpringBootApplication标注的类)的所在包以及下面所有子包里面的所有组件扫描到Spring容器。new PackageImports(metadata).getPackageNames().toArray(new String[0])就是指向包扫描的路径。

?
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
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));
}
}
@AutoConfigurationImportSelector
? ?AutoConfigurationImportSelector的作用是导入哪些组件的选择器。将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中;也会给容器导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件,这样节省去我们自己配置的麻烦。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
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);
}
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}

?
|