iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何正确的使用@SpringBootApplication注解
  • 953
分享到

如何正确的使用@SpringBootApplication注解

2023-06-14 12:06:24 953人浏览 独家记忆
摘要

如何正确的使用@SpringBootApplication注解?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。对springBoot工程的自动配置很感兴趣,于是学习其源码并整

如何正确的使用@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 {...}

可以看到这是一个复合注解,一共包括7个不同的注解,下面对这7个不同的注解进行分析。

2.1 注解

2.1.1 注解1:@Target({ElementType.TYPE})

用来表示注解作用范围,TYPE表示作用范围为类或接口。

如何正确的使用@SpringBootApplication注解

2.1.2 注解2:@Retention(RetentionPolicy.RUNTIME)

如何正确的使用@SpringBootApplication注解

2.1.3 注解3:@Documented

表明这个注释是由 javadoc记录的。

2.1.4 注解4:@Inherited

放在注解上,当父类加了@SpringBootApplication注解时,子类也会继承这个注解(对接口的实现类无效)。

2.1.5 注解5:@SpringBootConfiguration

底层仍是@Configuration注解, 源码如下:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {}
2.1.6 注解6:@ComponetScan

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

可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

2.2 注解:@EnableAutoConfiguration

个人感觉@EnableAutoConfiguration这个Annotation最为重要它的作用可以概括为:借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

其源码如下:

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

这里需要关注@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个注解。

2.2.1 注释:@AutoConfigurationPackage

源码如下:

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

可以发现这个注解的核心其实也是Import注解,表示对于标注该注解的类的包,应当使用AutoConfigurationPackages注册。接着看ReGIStrar这个类:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {    @Override      //metadata是我们注解所在的元信息    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {            //将我们注解所在包下所有的组件进行注册      register(registry, new PackageImport(metadata).getPackageName());    }    @Override    public Set<Object> determineImports(AnnotationMetadata metadata) {      return Collections.singleton(new PackageImport(metadata));    }}

这个类中的核心方法是register方法:

private static final String BEAN = AutoConfigurationPackages.class.getName();    public static void register(BeanDefinitionRegistry registry, String... packageNames) {    if (registry.containsBeanDefinition(BEAN)) {      BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);      ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();      constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));    }    else {      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();      beanDefinition.setBeanClass(BasePackages.class);      beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);      beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);      registry.registerBeanDefinition(BEAN, beanDefinition);    }}

register方法的逻辑非常清晰:如果这个bean已经被注册,就获取它的构造函数参数值,并将包名添加进去;否则就创建一个新的bean定义并进行注册。通过@AutoConfigurationPackage这个注解,可以将注解所在包下所有的组件进行注册。

2.2.2 注解:@Import(AutoConfigurationImportSelector.class)

这个注解导入了AutoConfigurationImportSelector这个类这个类的核心方法是selectImports方法,实现ImportSelector接口。方法基于我们在pom.xml文件中配置的jar包和组件进行导入。所以方法返回的是一个Class全路径的String数组,返回的Class会被Spring容器管理。方法源码如下:

@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {  if (!isEnabled(annotationMetadata)) {    return NO_IMPORTS;  }  AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader      .loadMetadata(this.beanClassLoader);  AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,      annotationMetadata);  return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

这个方法的结构也很清晰,首先通过isEnabled方法判断是否需要进行导入,如果需要导入的话,通过loadMetadata方法获取配置信息,并通过getAutoConfigurationEntry进行自动装配。isEnabled方法源码如下:

protected boolean isEnabled(AnnotationMetadata metadata) {  if (getClass() == AutoConfigurationImportSelector.class) {    return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);  }  return true;}

这个方法通过EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY这个配置项进行判断是否需要自动配置,默认为true。loadMetadata方法源码如下:

protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";  public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {    return loadMetadata(classLoader, PATH);  }  static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {    try {      Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)          : ClassLoader.getSystemResources(path);      Properties properties = new Properties();      while (urls.hasMoreElements()) {        properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));      }      return loadMetadata(properties);    }    catch (IOException ex) {      throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);    }  }  static AutoConfigurationMetadata loadMetadata(Properties properties) {    return new PropertiesAutoConfigurationMetadata(properties);  }

可以看到这个方法会加载META-INF/spring-autoconfigure-metadata.properties下的所有配置信息并包装成AutoConfigurationMetadata对象返回。

注:spring-autoconfigure-metadata.properties文件在spring-boot-autoconfigure-2.1.9.RELEASE.jar/META-INF下。

getAutoConfigurationEntry方法源码如下:

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,      AnnotationMetadata annotationMetadata) {    if (!isEnabled(annotationMetadata)) {      return EMPTY_ENTRY;    }    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 new AutoConfigurationEntry(configurations, exclusions);}

这个方法是AutoConfiguration的主流程方法,可以将这个方法的每一行看做一个步骤,那么处理步骤如下:

 加载配置了@EnableAutoConfiguration注解的属性值getAttribute方法:

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {    String name = getAnnotationClass().getName();    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));    Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()        + " annotated with " + ClassUtils.getShortName(name) + "?");    return attributes;}

得到META-INF/spring.factories文件中以@EnableAutoConfiguration完全限定类名做key的value,getCandidateConfigurations方法:

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;}protected Class<?> getSpringFactoriesLoaderFactoryClass() {    return EnableAutoConfiguration.class;}

其中,SpringFactoriesLoader.loadFactoryNames()这个方法的作用是使用给定的类加载器从META-INF/spring.factories加载给定类型的工厂实现的完全限定类名;

去重;

得到需要排除的类的类名,这些类可以在@EnableAutoConfiguration注解中配置;

检查这两个集合

把需要排除的类移除;

根据OnBeanCondition、OnClassCondition等条件进行过滤(有兴趣可以深入了解);

广播事件,得到AutoConfigurationImportListener所有实现类,然后生成事件进行广播;

把需要装配和排除的类完全限定名封装成了AutoConfigurationEntry对象返回。

因此,@EnableAutoConfiguration可以简单总结为:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中EnableAutoConfiguration对应的配置项通过反射实例化为对应的标注了@Configuration的IoC容器配置类,并加载到IoC容器。

关于如何正确的使用@SpringBootApplication注解问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网精选频道了解更多相关知识。

--结束END--

本文标题: 如何正确的使用@SpringBootApplication注解

本文链接: https://www.lsjlt.com/news/270933.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何正确的使用@SpringBootApplication注解
    如何正确的使用@SpringBootApplication注解?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。对SpringBoot工程的自动配置很感兴趣,于是学习其源码并整...
    99+
    2023-06-14
  • 如何正确使用注解
    本篇内容介绍了“如何正确使用注解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!日志脱敏场景简介在日志里我们的日志一般打印的是 model 的...
    99+
    2023-06-16
  • @SpringBootApplication注解的使用
    目录一、前言 二、正文 2.1 注解 2.1.1 注解1:@Target({ElementType.TYPE})2.1.2 注解2:@Retention(RetentionPolic...
    99+
    2024-04-02
  • 如何在Java中正确的使用注解
    如何在Java中正确的使用注解?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。注解是jdk1.5新增的特性.大家都知道,jdk1.5在java的发展史上有着划时代的意义.而注...
    99+
    2023-05-31
    java 注解 ava
  • SpringBoot中@Import注解如何正确使用
    目录简介一、功能简介二、示例1.引入普通类2.引入ImportSelector的实现类(1)静态import场景(注入已知的类)(2)动态import场景(注入指定条件的类...
    99+
    2024-04-02
  • 如何正确使用Python中的函数注释
    本篇内容主要讲解“如何正确使用Python中的函数注释”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何正确使用Python中的函数注释”吧!我在查看python的fixture源码时发现 fi...
    99+
    2023-06-15
  • 如何正确规范使用论文脚注
    论文中的脚注有很多种,根据不同学校的要求来定,这个需要涉及到Word的使用,很多同学不会使用Word,我这里说的不会使用,不是指不会打开Word输入文字,而是里面的许多功能我们先讲一下什么是脚注。脚注,是汉语词汇,汉语拼音为就是可以附在文章...
    99+
    2023-06-03
  • 如何正确的使用WeakHashMap
    这篇文章给大家介绍如何正确的使用WeakHashMap,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 在学习WeakHashMap时了解到,如果map里面的key只有map本身引用时,就会将key对应的Entry清除掉...
    99+
    2023-05-30
    weakhashmap
  • 如何正确的使用JDBC
    今天就跟大家聊聊有关 如何正确的使用JDBC,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。什么是JDBCJDBC(Java Database Connectivity),即Java数...
    99+
    2023-05-31
    jdbc jdb
  • 如何正确的使用 jsonpath
    今天就跟大家聊聊有关如何正确的使用 jsonpath,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。java项目demo:注意: 其中他的max,min,avg,stddev函数只能类...
    99+
    2023-06-06
  • 如何正确的使用supervisor
    这期内容当中小编将会给大家带来有关如何正确的使用supervisor,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。软硬件环境centos7.6.1810 64bitcat /etc/redhat...
    99+
    2023-06-06
  • 如何正确的使用JAXB
    这期内容当中小编将会给大家带来有关如何正确的使用JAXB,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、jaxb是什么     JAXB是Java Archite...
    99+
    2023-05-31
    jaxb
  • 如何正确的使用TypeScript
    如何正确的使用TypeScript,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、TypeScript 是什么TypeScript 是一种由微软开发的自由和开源的编程语言...
    99+
    2023-06-17
  • 如何正确的使用Puppet
    今天就跟大家聊聊有关如何正确的使用Puppet,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1. 概述 puppet是一个开源的软件自动化配置和部署工具,它使用简单且功能强大,正得到...
    99+
    2023-06-12
  • 如何正确的使用pytest
    本篇文章为大家展示了如何正确的使用pytest,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1、安装pytest,打开dos窗口输入:pip install pytest2、通过pycharm工具下...
    99+
    2023-06-07
  • 如何正确的使用CMake
    如何正确的使用CMake?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makef...
    99+
    2023-06-08
  • 如何正确的使用numpy.sum()
    这篇文章给大家介绍如何正确的使用numpy.sum(),内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。numpy的sum函数可接受的参数是:sum(a, axis=None, dtype=None,&...
    99+
    2023-06-15
  • 如何正确的使用Gradle
    本篇文章为大家展示了如何正确的使用Gradle,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、Gradle相比Maven的优势配置简洁Maven是用pom.xml管理,引入一个jar包至少5行代码...
    99+
    2023-06-06
  • 如何正确的使用javascript
    本篇文章为大家展示了如何正确的使用javascript,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。使用javascript的方法:可以用script标签引入<script type...
    99+
    2023-06-14
  • 如何正确的使用springcloud
    这期内容当中小编将会给大家带来有关如何正确的使用springcloud,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、微服务简介 Ⅰ、我对微服务的理解微服务是软件开发的一种架构方式,由单一的应用小程序构...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作