自学内容网 自学内容网

Springboot自动装配源码分析

概要

在spring中,使用xml的方式将定义的bean加载到ioc容器中是最原始的定义方式,3.x 后,支持注解来加载bean。spring注解的方式总结下来只要有以下几种:

  1. Configration + ComponentScan配置在配置类中,然后需要定义的bean,在类上加上Controller、Service、Component等注解
@Configuration
@ComponentScan({"anno"})
public class ParentScan {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ParentScan.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }
}

// 其中Service1类如下
@Service
public class Service1 {
   public void go(){
       System.out.println("service1 .....");
   }
}

  1. 使用Configration注解,同时在配置类中使用Bean注解定义bean
@Configuration
public class BeanScan {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScan.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }

    @Bean
    Service1 service1(){
        return new Service1();
    }
   
}
  1. Configration + Import,其中Import可以是配置类,也可以是普通类
@Configuration
@Import(ParentScan.class)
public class ImportConfig {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportConfig.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }
}
@Configuration
@ComponentScan({"anno"})
public class ParentScan {
}

@Configuration
@Import({Service1.class})
public class ImportBean {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportBean.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }

}
  1. Configration + Import+ImportSelector的方式
@Configuration
@Import(MySelector.class)
public class ImportSelector {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ImportSelector.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }
}

public class MySelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{
                Service1.class.getName()
        };
    }
}


  1. 还可以采用自定义注解EnableXXX的方式
@Configuration
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableMySelector {
}

@EnableMySelector
public class MyEnable {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyEnable.class);
        Service1 service1 = context.getBean(Service1.class);
        service1.go();
    }
}

在测试用例中,用到的ApplicationContext实现类是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

在这里插入图片描述
其类关系图:
在这里插入图片描述
在ioc容器的处理过程,后置处理器org.springframework.context.annotation.ConfigurationClassPostProcessor会加载处理到带有@Configuration注解的类

@SpringBootApplication

@Target(ElementType.TYPE)//该注解只能声明在一个类前
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Documented//表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的
@Inherited//表示该注解会被子类继承
@SpringBootConfiguration// ===> 继承自@Configuration,二者功能也一致,标注当前类是配置类
@EnableAutoConfiguration//===> 自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

/**排除指定的自动装配的类型
 * Exclude specific auto-configuration classes such that they will never be applied.
 * @return the classes to exclude
 */
@AliasFor(annotation = EnableAutoConfiguration.class)
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
 */
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};


@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};//扫描指定的包

@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};//扫描指定包中的类


//指定 bean 名称生成器
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

//配置 @Bean 注解的方法返回的 bean 是否需要被代理,默认为 true,需要被代理。使用 CGLIB 增强代理
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;

}

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented// 表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的
@Inherited//表示该注解会被子类继
@AutoConfigurationPackage// ===> 自动配置包,  作用:将main包下的所组件注册到容器中
//@Import的作用就是导入一个类到IOC容器
@Import(AutoConfigurationImportSelector.class)// ===> 核心AutoConfigurationImportSelector的方法selectImports
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 {};

}

在这个注解下我们需要关注两个注解@AutoConfigurationPackage·,@Import({AutoConfigurationImportSelector.class})

@AutoConfigurationPackage

在这里插入图片描述

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//new PackageImports(metadata).getPackageNames()返回一个主包名称
//这个包就是Spring Boot主配置类所在的包,metadata,返回主配置类
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
          //如果存在这个bean定义
if (registry.containsBeanDefinition(BEAN)) {
BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
} else {
//不存在就注册(在这个package路径下的org.springframework.boot.tests.hibernate52)
registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
}
}

@Import({AutoConfigurationImportSelector.class}

关键方法:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports

在这里插入图片描述

//getAutoConfigurationEntry()方法返回所有带有@Configuration注解的类的全类名,
//Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取到这个数组,
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//发现configurations的结果是所有的xxxAtuoConfiguration类,配置类一共124个
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 List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//打开spring-boot-autoconfigure/META-INF/spring.factories
//132个,随便选一个进去看看
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());  // ===> loadFactoryNames  ,  getSpringFactoriesLoaderFactoryClass
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;  //返回需要加载的 Configration 类的名字
}

其中的org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames方法,最终会去加载spring-boot-autoconfigure中的spring.factories文件
在这里插入图片描述
注意的是,在代码中加载的时候并不是全部加载这些配置类,而是根据bean的加载条件进行加载,这时候@ConditionalOnxxx注解发挥作用了。


原文地址:https://blog.csdn.net/weixin_42612223/article/details/140639185

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!