springboot自动装配

1. 何为自动装配

springboot相较于spring的一大优势就是springboot自动装配,那么何为自动装配呢?
在我们之前使用spring进行开发的时候,我们需要通过XML配置文件配置我们所需要的Bean对象到spring容器中,例如:

<bean id="jedisConnectionFactory" class="...JedisConnectionFactory"></bean>
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"></bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"></bean>

但是这样并不是很方便,一来配置XML配置文件比较复杂且麻烦,二来XML配置文件如果有错误,排查问题起来会比较慢。
springboot就通过自动装配避免使用XML配置文件,可以通过配置yml或者properties配置文件,就可以将我们所需要的Bean对象加载到spring容器中。
其实自动装配就是spring自动帮你把所需要的Bean对象进行装配注入到spring容器中。

2. 自动装配的优势

自动装配有以下优势:
1、配置简单,避免使用大量XML方式进行配置。
2、提高开发效率。

3. 自动装配原理

3.1 @SpringBootApplication

要弄懂springboot的自动装配,首先需要了解@SpringBootApplication这个注解。

@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我们发现在这个注解上还有几个注解:@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan,表示这个注解是一个组合注解,同时拥有上面这三个注解的功能。

3.2 @SpringBootConfiguration

@SpringBootConfiguration注解,本质上是一个@Configuration注解。可以理解启动类就是一个配置类。

3.3 @ComponentScan

@ComponentScan注解是包扫描注解,等同于XML<context:component-scan>标签,目的是用来扫描包路径。如果不指定路径,默认加载的是启动类所在目录下面所有的对象。

3.4 @EnableAutoConfiguration

@EnableAutoConfiguration注解,该注解是开启自动配置,添加了该注解就会自动将spring扫描到的Bean对象加载到容器中。
我们重点看下@EnableAutoConfiguration这个注解。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

该注解通过@Import({EnableAutoConfigurationImportSelector.class})注解来进行装配,EnableAutoConfigurationImportSelector该类实现了ImportSelector接口。在父类AutoConfigurationImportSelector中可以看到接口方法的实现。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            //1加载META-INF/spring-autoconfigure-metadata.properties文件
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            //2获取注解的属性及其值(PS:注解指的是@EnableAutoConfiguration注解)
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //3.在classpath下所有的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,并将其封装到一个List中返回
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //4.对上一步返回的List中的元素去重、排序
            configurations = this.removeDuplicates(configurations);
            //5.依据第2步中获取的属性值排除一些特定的类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            //6对上一步中所得到的List进行过滤,过滤的依据是条件匹配。这里用到的过滤器是
            //org.springframework.boot.autoconfigure.condition.OnClassCondition最终返回的是一个ConditionOutcome[]
            //数组。(PS:很多类都是依赖于其它的类的,当有某个类时才会装配,所以这次过滤的就是根据是否有某个
            //class进而决定是否装配的。这些类所依赖的类都写在META-INF/spring-autoconfigure-metadata.properties文件里)
            this.checkExcludedClasses(configurations, exclusions);
            // 移除需要排除的信息
            configurations.removeAll(exclusions);
            // 过滤,检查候选配置类上的注解@ConditionalOnClass,如果要求的类不存在,则这个候选类会被过滤不被加载
            configurations = this.filter(configurations, autoConfigurationMetadata);
            // 广播事件
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            // 返回要被加载的类数组
            return StringUtils.toStringArray(configurations);
        }
    }

该方法刚开始会先判断是否进行自动装配,然后会调用getCandidateConfigurations方法,通过SpringFactoriesLoader读取META-INF/spring.factories配置文件,然后对其进行过滤并移除,然后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
        List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
        if (!listeners.isEmpty()) {
            AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
            Iterator var5 = listeners.iterator();

            while(var5.hasNext()) {
                AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
                this.invokeAwareMethods(listener);
                listener.onAutoConfigurationImportEvent(event);
            }
        }

    }

我使用的springboot是1.5.22.REALEASE版本,该版本中EnableAutoConfigurationImportSelector已经弃用。

4. 总结

springboot 自动装配其实就是通过扫描配置,将所需要的Bean对象以JavaConfig的方式注入到Spring容器中,是通过SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,最终通过过滤和移除确定哪些是需要被装载的类,从而交给spring容器装配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值