zoukankan      html  css  js  c++  java
  • springboot源码@SpringBootApplication注解分析

    首先是@SpringBootApplication(自动化装配功能)

    点进去源码发现

     先来看看每个注解的意思

    可以发现它是由众多注解组合而成的,下面具体分析下这里每个注解所起到的作用。

    • @Target Target通过ElementType来指定注解可使用范围的枚举集合(FIELD/METHOD/PARAMETER...)
    • @Retention Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值:

      • RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
      • RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
      • RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使
    • @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中
    • @Inherited 允许子类继承父类的注解,仅限于类注解有用,对于方法和属性无效。
    • @SpringBootConfiguration 注解实际上和@Configuration有相同的作用,配备了该注解的类就能够以JavaConfig的方式完成一些配置,可以不再使用XML配置。
    • @ComponentScan 这个注解完成的是自动扫描的功能,相当于Spring XML配置文件中的:<context:component-scan>,可使用basePackages属性指定要扫描的包,及扫描的条件。如果不设置则默认扫描@ComponentScan注解所在类的同级类和同级目录下的所有类,所以我们的Spring Boot项目,一般会把入口类放在顶层目录中,这样就能够保证源码目录下的所有类都能够被扫描到。
    • @EnableAutoConfiguration 这个注解是让Spring Boot的配置能够如此简化的关键性注解。

    其实主要重要的注解就是标红的这三个注解:下面我们着重分析这三个注解。

    1)@ComponentScan:就像上面所说,ComponentScan一般在spring中主要是用于:

    @ComponentScan用于类或接口上主要是指定扫描路径,spring会把指定路径下带有指定注解的类自动装配到bean容器里,会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等,其作用等同于<context:component-scan base-package="com.maple.learn" />配置。

    而在springboot中,如果你的其他包都在使用了@SpringBootApplication注解的main app所在的包及其下级包,则你什么都不用做,SpringBoot会自动帮你把其他包都扫描了,如果你有一些bean所在的包,不在main app的包及其下级包,那么你需要手动加上@ComponentScan注解并指定那个bean所在的包。(后面在解释在这里的原理

    2)@SpringBootConfiguration :先来一张其源码截图

     这里说明SpringBootConfiguration 其实是对spring的@Configuration的封装,相当于一个配置类,注解主要标注在某个类上,相当于xml配置文件中的<beans>。并会将当前类内声明的一个或多个以@Bean注解的方法的实例纳入到spring容器中,并且实例名就是方法名。本身其实也是一个IoC容器的配置类

    3)@EnableAutoConfiguration 这个才是重点,点击源码发现

     先来聊聊这个注解:@AutoConfigurationPackage

    AutoConfigurationPackage注解的作用是将 添加该注解的类所在的package 作为 自动配置package 进行管理。

    AutoConfigurationPackage注解:

    复制代码
    复制代码
    1     static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    2 
    3         @Override
    4         public void registerBeanDefinitions(AnnotationMetadata metadata,
    5                 BeanDefinitionRegistry registry) {
    6             register(registry, new PackageImport(metadata).getPackageName());
    7         }
    复制代码
    复制代码

    它其实是注册了一个Bean的定义。

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

    以上图为例,DemoApplication是和demo包同级,但是demo2这个类是DemoApplication的父级,和example包同级

    也就是说,DemoApplication启动加载的Bean中,并不会加载demo2,这也就是为什么,我们要把DemoApplication放在项目的最高级中。

    这里来谈谈其与componentScan的区别:

    在默认的情况下就是将:主配置类(@SpringBootApplication)的所在包及其子包里边的组件扫描到Spring容器中。

    • 看完这句话,会不会觉得,这不就是ComponentScan的功能吗?这俩不就重复了吗?

            看看文档的这句话:

    it will be used when scanning for code @Entity classes.
    It is generally recommended that you place EnableAutoConfiguration (if you’re
    not using @SpringBootApplication) in a root package so that all sub-packages
    and classes can be searched.

    比如说,你用了Spring Data JPA,可能会在实体类上写@Entity注解。这个@Entity注解由@AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由ComponentScan来扫描并加载的。

    简单理解:这二者扫描的对象是不一样的。

     4)下面来看看一个重中之重的注解:@EnableAutoConfiguration

    老规矩进行这个重要注解之前,要先铺垫一些其用到的知识,不然的话,不能到时候懵懵懂懂的。接下来看看这个@Import这个注解,他是来干什么的呢?

    @Import注释,根据字义,我们可以理解为导入组件选择器自动配置,作用是将需要导入的组件以全类名的方式返回,这些组件将被添加到Spring容器中,如图:

    自动配置类的作用,配置注入功能组件自动完成。

    a.允许使用@Configuration注解的类

    这个比较简单,如果明确知道需要引入哪个配置类,直接引入就可以。

    b.允许是实现ImportSelector接口的类

    如果并不确定引入哪个配置类,需要根据@Import注解所标识的类或者另一个注解(通常是注解)里的定义信息选择配置类的话,用这种方式。

    c.Spring会把实现ImportSelector接口的类中的SelectImport方法返回的值注入到Spring容器中(即IOC容器)。这个方法的返回值必须是一个class的全类名的String[]。
    比较典型的注解:

    好吧,简单了解这个之后,下面来谈谈重点吧:

    @EnableAutoConfiguration刚才已经贴了一张图了,点开源码之后就是

    继续点击进去,你会发现:

     

     

     一路点下去,发现AutoConfigurationImportSelector实现了父类接口ImportSelector,并且重写了父类的selectImports的方法。

     在这个方法中,其实主要实现是看configurations这个里面返回的是什么东西就行了。

    继续点进去这个方法

     继续点击进去

     这个时候,我们就豁然开朗了,原来最终我们是要找“META-INF/spring.factories”这个配置文件啊!

    但是这个东西实在哪里呢,来看看我们引入的mavenjar包吧。

     原来是这个东西,看看里面是什么

     是不是明白了,***AutoConfiguration,这个不就是我们上面的注解的形式吗?

    上图里面这么多的xxxAutoConfiguration就是我们的这么久得出的结果,最终就是加载这么多的类的全路径,然后springboot内部就是实例化这些类并加载到容器里面,完成springboot应用启动时的自动配置。

    来看看下面这样图,他们大神画的生动的图,让人豁然开朗:

    自动配置幕后英雄:SpringFactoriesLoader详解

    借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

    SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置。

    复制代码
    public abstract class SpringFactoriesLoader {
        //...
        public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
            ...
        }
    
    
        public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            ....
        }
    }
    复制代码

    配合@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类

    上图就是从SpringBoot的autoconfigure依赖包中的META-INF/spring.factories配置文件中摘录的一段内容,可以很好地说明问题。

    所以,@EnableAutoConfiguration自动配置的魔法骑士就变成了:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

     在来探讨一个问题:springboot的启动类其实基本上就两部分,一部分是spring-boot-starter,另一部分是spring-boot-autoconfig,starter里面其实没有什么东西,就是依赖了autoconfig。

    这么多的***AutoConfiguration,点进去过去会自动调到对应的启动类源码,在启动类中还有一个配置类***Properties,这个是默认自带的,例如:这个是activemq的默认配置类(默认的配置类)

     在这里,ActiveMQAutoConfiguration的源码会关联这个配置文件,这样他们就可以连在一起,最直接的体现就是,我们在application.properties或者applciation.yml中可以提示配置文件的属性

    这样的话,整个启动类的思路就比较清晰了。

    总结:

    @ConditionalOnXX 条件判断注解,通过条件来判断这个类是否生效!

     随便拿一个启动器举例子:

     1:springboot启动的时候会加载大量的自动配置类。spring.factories

     2:我们就需要判断我们的类是否在这个里面,如果不存在,我们需要手动导入,如果存在,导入启动器即可。

     3:我们的配置文件(application.yml或者application.properties)之所以可以自动配置生效:

           (1)xxxAutoConfiguation:自动配置类,根据条件@ConditionalOnXX来进行判断是否生效,如果生效则成功注入bean

           (2)xxxProperties:封装配置文件的相关属性

    4:给容器中自动配置属性的时候,会通过xxxProperties来获取某用户的配置文件中的属性,如果没有则使用默认,有则使用自己配置的。

    (未完待续........)


    本文引用文章声明:
    原文链接:https://blog.csdn.net/neulily2005/article/details/83750027 -------CSDN博主「Mr.甘」

    原文链接:https://blog.csdn.net/mapleleafforest/article/details/86623578----------CSDN博主「a maple leaf」

    原文链接:https://www.cnblogs.com/shamo89/p/8184960.html------那啥快看[博客园]

    原文链接:http://www.imooc.com/article/275453?block_id=tuijian_wz---Java3y[慕课网]

    原文链接:https://www.cnblogs.com/henianxi/p/9950406.html

  • 相关阅读:
    vs2008.net多语言实现方法
    C#中 Process的扩展类ProcessExtensions
    C#获取当前系统信息的类
    非常好用的GridView控件yyControls中的SmartGridView
    Android提供两个常用的消息弹出框【Toast和Alert】
    [置顶] Asp.net中实现多语言的Page的扩展的基类
    C# word类库
    在系统出现未处理的错误时,在Global的Application_Error记录下错误
    向大家推荐一个非常好用的JS日历控件My97DatePicker
    网页代码测试工具集合
  • 原文地址:https://www.cnblogs.com/clover-forever/p/12521386.html
Copyright © 2011-2022 走看看