SpringBoot自动装配原理--------@SpringBootApplication注解

本文主要讲解@SpringBootApplication注解的一个底层原理,也就是springboot启动类的那个注解,run()方法会在下一篇文章进行讲解。

1.什么是SpringBoot?

SpringBoot是一个能够快速开发应用的一个框架,它简化了基于 Spring 的应用开发,通过少量的代码就能创建一个独立的、产品级别的 Spring 应用。为 Spring 平台及第三方库提供开箱即用的设置,它的核心思想就是约定大于配置,其中的应用只需要很少的 Spring 配置,就能够直接使用。这样就大大的简化了你的开发模式。

2.SpringBoot的自动装配原理

启动类:

@SpringBootApplication
public class ApplicationTest {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationTest.class);
    }
}

点开@SpringBootApplication注解,你会看到如下代码,说明该注解是一个组合注解,虽然有多个注解,但是最主要的注解就是以下三个:
@SpringBootConfiguration(里面应用了@Configuration)
@EnableAutoConfiguration
@ComponentScan

@Target(ElementType.TYPE)            // 注解的适用范围,其中TYPE用于描述类、接口(包括包注解类型)或enum声明
@Retention(RetentionPolicy.RUNTIME)  // 注解的生命周期,保留到class文件中(三个生命周期)
@Documented                          // 表明这个注解应该被javadoc记录
@Inherited                           // 子类可以继承该注解
@SpringBootConfiguration             // 继承了Configuration,表示当前是配置类
@EnableAutoConfiguration             // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan(excludeFilters = {    // 扫描路径设置(具体使用待确认)
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type=FilterType.CUSTOM,classes=AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

所以说你用这个三个注解来代替@SpringBootApplication注解,你的启动类也是可以启动的。

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class ApplicationTest {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationTest.class);
    }
}

接下来讲解各个注解的含义。

2.1 SpringBootConfiguration注解:

@SpringBootConfiguration注解点开查看发现里面应用了@Configuration注解

@Configuration:
1.这里的@Configuration,它就是JavaConfig形式的Spring Ioc容器的配置类所使用的那个注解@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,它本身也是一个IoC容器的配置类。

2.配置spring容器有两种方式,一种是javaConfig形式,一种是XML配置文件形式。

javaConfig形式:

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

@Configuration
public class UserConfiguration{
    @Bean
    public UserService userService(){
        return new UserServiceImpl();
    }
}

xml形式:

<bean id="userService" class="UserServiceImpl">
...
</bean>

2.2 @ComponentScan注解:

1.它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

2.我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则Spring框架默认会从声明@ComponentScan所在类的 package下进行扫描。

3.所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

2.3 @EnableAutoConfiguration:

该注解也是一个组合注解,主要是用到@AutoConfigurationPackage和@Import,这两个注解

  1. @AutoConfigurationPackage:
    这个注解主要是通过@Import(AutoConfigurationPackages.Registrar.class)注解,它将Registrar类导入到容器中,而Registrar类作用是扫描主程序类同级包以及子级包,将同级包及所有子包下的 组件 放到spring容器中

以下是源码:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
     @Override
      public void registerBeanDefinitions(AnnotationMetadata metadata,
        BeanDefinitionRegistry registry) {
             register(registry, new PackageImport(metadata).getPackageName());
        }

new PackageImport(metadata).getPackageName()方法,它其实返回了当前主程序类的同级以及子级的包组件

  1. @Import(AutoConfigurationImportSelector.class):
    该注解主要是通过导入AutoConfigurationImportSelector 类,借助该类中重写了父类的一个方法,名为selectImports( ),这个方法它先通过@EnableAutoConfiguration的类路径
    org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,从classpath中搜寻所有的META-INF/spring.factories配置文件,来获取value值,值就是一组@Configuration自动配置类,然后通过反射(Java Refletion)实例化为对应 的标注了@Configuration的IoC容器配置类,然后汇总为一个并通过SpringFactoriesLoader来进行一系列的容器创建过程。
    下图为 AutoConfigurationImportSelector类的继承关系:
    在这里插入图片描述

可以从图中看出 AutoConfigurationImportSelector 继承了 DeferredImportSelector 继承了 ImportSelector
而ImportSelector有一个方法为:selectImports( )。

下图为 selectImports( )方法的源码:

@Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return StringUtils.toStringArray(configurations);
    }

可以看到方法中第六行代码,getCandidateConfigurations(annotationMetadata,attributes);
从classpath中搜寻所有的META-INF/spring.factories配置文件。这个外部文件,有很多自动配置的类。
如下图:
在这里插入图片描述

该文件可以在spring-boot-autoconfigure.jar包中的MATE-INF找到

  1. 其实在这些配置类中都有类似@Conditional注解,像@ConditionalOnClass的含义是指定的类必须存在于类路径下,
    比如:MongoDB的自动配置类
    MongoDataAutoConfiguration类中声明了类路径下必须含有Mongo.class, Mongo Template.class这两个类,否则该自动配置类不会被加载。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值