SpringBoot自动装配原理

要了解SpringBoot的自动装配原理, 我们结合SpringBoot的源码一步步分析.

首先在所有的SpringBoot项目中, 一定会有一个注解@SpringBootApplication.
对于@SpringBootApplication这个注解, 相信接触过SpringBoot项目的小伙伴都会非常熟悉, 这是SpringBoot的一个核心注解, 这个注解一般会贴在我们的启动类中, 代表这是SpringBoot的一个主配置类.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

观察@SpringBootApplication源码我们可以发现, @SpringBootApplication实际上是一个复合注解, 里面包含了七个注解.
@Target 的作用是设置@SpringBootApplication注解的使用范围, 括号里面的参数 ElementType.TYPE, 表示@SpringBootApplication注解可以使用在接口, 类, 枚举, 注解中.
@Retention 的作用是设置@SpringBootApplication注解的生命周期, 类似于maven依赖的生命周期一样, 括号的参数 RetentionPolicy.RUNTIME 表示运行加载到字节码文件时, 注解依然生效.
@Documented 的作用是, 设置@SpringBootApplication注解可以使用在文档类的文件中.
@Inherited 的作用是设置子类可以继承父类的注解.

以上四个注解都是 Java 提供的原生注解, 可能有些小伙伴早就了解了, 但是为了方便不知道的小伙伴, 啰嗦一点也要说完啦!

@SpringBootConfiguration, 熟练的小伙伴估计一眼就能看出来这个注解的作用就是配置类, 我们可以继续查看 @SpringBootConfiguration 的定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

这里面实际上就是一个马甲注解, 里面就是一个 @Configuration注解, 所以这个注解的作用是表示当前类是一个配置类.

@ComponentScan, 表示会扫描@SpringBootApplication所在的当前包及其子包下的内容.

与自动装配相关的注解来了:
@EnableAutoConfiguration 这个注解的作用就是开启自动装配功能.

我们继续跟进查看@EnableAutoConfiguration的相关源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

在@EnableAutoConfiguration的源码中, 我们凭感觉基本可以一眼就能注意到这个类的重点, 没错, 相信自己的直觉:
在这里插入图片描述
在这个类中, 通过 @import直接, 引用了另外一个类EnableAutoConfigurationImportSelector, 通过这个类的名称, 我们其实可以见名知意: 自动配置导入选择器类, 可想而知, 这个类的重要性. 我们继续查看这个类具体的核心工作是什么.
此时我们会发现, 这个类中, 只定义了一个方法, 而且这个方法看起来跟我们的自动装配没有多大关系. 但是既然这是一个选择器类, 那么它的功能一定是有相关选择具体哪些bean需要自动装配的相关功能实现的, 不可能只有这么一点代码. 此时我们可以看到, 这个类是继承于 AutoConfigurationImportSelector 类, 那我们继续查看其父类, 实现会不会就是在父类里面呢.

此时我们发现, 这个类里面会有很多方法, 而核心的方法就是

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的静态方法, 所以我们继续点击进去

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String propertyValue = properties.getProperty(factoryClassName);
                String[] var8 = StringUtils.commaDelimitedListToStringArray(propertyValue);
                int var9 = var8.length;

                for(int var10 = 0; var10 < var9; ++var10) {
                    String factoryName = var8[var10];
                    result.add(factoryName.trim());
                }
            }

            return result;
        } catch (IOException var12) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var12);
        }
    }

而这里最重要的一步, 就是通过一个类加载器, 到classpath里面加载文件的内容, 而路径就是
META-INF/spring.factories.
而我们可以观察, 如果是SpringBoot集成的Jar, 它里面的文件结构基本都是这样的:
在这里插入图片描述
观察可以发现, 在这些Jar包里面, 都会有一个META-INF文件, 并且在这个文件中, 都会有一个文件spring.factories. 而spring.factories文件内容我们一德鲁伊连接池为例

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

这里面实际上就是指定了, 自动装配德鲁伊连接池时, 需要加载的配置类, 开发人员在这个配置类里面, 设置了许多默认的配置, 而SpringBoot的所做的自动装配工作, 就是通过这个配置类, 通过这些默认的配置, 或者加上我们手动在SpringBoot配置文件中配置的内容, 如德鲁伊连接池, 我们需要配置数据库连接的三要素, 通过这些一系列的配置, SpringBoot就能成功把德鲁伊连接池这个bean初始化出来供我们使用, 其他的bean自动装配也是类似, 可能有些bean甚至只需要我们导入相关的依赖, SpringBoot即可通过默认配置完成bean的创建和初始化, 所以相对于Spring来说, SpringBoot可以通过这个自动装配, 剩下许多不需要重复的配置, 但是实际上这些配置是存在的, 只不过已经默认写在了代码中而已.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值