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注解发挥作用了。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值