Spring原理—加载Bean

上篇文章:

SpringBoot系列—统一功能处理(统一异常处理)https://blog.csdn.net/sniper_fandc/article/details/148998405?fromshare=blogdetail&sharetype=blogdetail&sharerId=148998405&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

1 Spring加载Bean

1.1 @ComponentScan注解

1.2 @Import注解

2 SpringBoot自动装配

2.1 @SpringBootApplication注解

2.2 @SpringBootConfiguration注解

2.3 @ComponentScan注解

2.4 @EnableAutoConfiguration注解


1 Spring加载Bean

        在使用Spring以及SpringBoot时,会发现很多时候并没有声明某个类需要Spring来管理,就可以直接注入到程序中使用,这是因为Spring和SpringBoot为我们已经做好了一些Bean的加载:

        通常Spring会识别到@SpringBootApplication注解所在的目录下的包和类以及对应的注解,但是如果不是这个路径下有一些代码(第三方jar包会在类加载时期合并到src/main/java路径下),如果不做一些配置,Spring就无法识别到这些路径下的代码。在Spring中有两种方式可以实现加载Bean时的路径扫描:

1.1 @ComponentScan注解

        使用方法在@SpringBootApplication所在的启动类添加@ComponentScan("全路径的包名"),可以让Spring扫描该路径下的所有内容。

        缺点:扫描范围太大,会扫描大量不需要管理的依赖项。

1.2 @Import注解

        使用方法在@SpringBootApplication所在的启动类添加@Import("类.class"),可以让Spring扫描该类。

        缺点:扫描范围太小,多个类需要管理就需要写多个类名。

        上述两种方式都有缺点,并且程序员也不知道第三方依赖哪些类需要被管理。但是如果第三方依赖可以提供一个需要管理的清单,把两个注解结合一下,在通过一个文件管理需要扫描的路径,由@Import来导入这个文件,就可以更灵活方便的完成Bean的扫描和加载了。SpringBoot就是采用这种方式:

2 SpringBoot自动装配

2.1 @SpringBootApplication注解

        SpringBoot对Spring进行了封装,在@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 {

    @AliasFor(

        annotation = EnableAutoConfiguration.class

    )

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



    @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 {};



    @AliasFor(

        annotation = ComponentScan.class,

        attribute = "nameGenerator"

    )

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;



    @AliasFor(

        annotation = Configuration.class

    )

    boolean proxyBeanMethods() default true;

}

        其中,@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan注解最关键。

2.2 @SpringBootConfiguration注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

        @SpringBootConfiguration的元注解是@Configuration和@Indexed注解(索引,加速启动),即让启动类被Spring扫描到。

2.3 @ComponentScan注解

        @ComponentScan注解用来进行路径过滤和自定义的路径扫描,可以通过basePackageClasses或basePackages来定义要扫描的特定包,如果没有定义特定的包,将从声明该注解的类的包开始扫描,这也是为什么SpringBoot项目声明的注解类必须要在启动类的目录下。

2.4 @EnableAutoConfiguration注解

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";



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



    String[] excludeName() default {};

}

        最关键的注解是@EnableAutoConfiguration,负责第三方依赖的配置类(@Bean注解的方法获得第三方依赖的对象)和组件(比如MyBatis的@Mapper注解不属于Spring)的扫描,其中包含两个关键注解:@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})。

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({AutoConfigurationPackages.Registrar.class})

public @interface AutoConfigurationPackage {

    String[] basePackages() default {};



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

}

        @AutoConfigurationPackage注解把启动类所在的包下面所有的组件都注入到Spring容器中。

而@Import注解负责把AutoConfigurationImportSelector类导入进来,在该类中的方法:

    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;

    }

        该方法通过Spring工厂的SpringFactoriesLoader.loadFactoryNames方法来自动加载配置类,扫描路径META-INF/spring.factories,该文件会给出第三方依赖需要加载的Bean的路径,但是需要按@ConditionalOnClass注解(需要注入)和@ConditionalOnMissingBean注解(忽略该Bean)来选择注入或者忽略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值