首页 > 其他分享 >SpringBoot-重要注解(1)

SpringBoot-重要注解(1)

时间:2024-03-07 19:33:59浏览次数:15  
标签:重要 SpringBoot class 注解 Import ImportAutoConfiguration public configurations

ConfigurationProperties 注解

https://blog.csdn.net/skh2015java/article/details/120141409

@Import、@ImportAutoConfiguration

https://www.cnblogs.com/imyjy/p/16092825.html

当我们需要在一个配置类中导入另一个 Configuration 配置类时,可以使用 @Import@ImportAutoConfiguration 注解:

@Configuration
@Import(MyOtherAutoConfiguration.class)
public class MyAutoConfiguration implements ImportAware {

}

@Configuration
@ImportAutoConfiguration(MyOtherAutoConfiguration.class)
public class MyAutoConfiguration implements ImportAware{

}

查看源码可以发现 @ImportAutoConfiguration 继承了 @Import 注解,所以核心是这个注解:

@Import 注解主要是用来替代 Spring XML 中的 <import/> 标签的,这个标签主要是用来解决配置混乱的,它支持我们将要声明的 bean 分类写入多个 XML 配置文件中。通过 @Import 能够将多个配置类集中整合到一起。但是 @Import 的使用场景十分局限,比如 (1)它导入的配置类集合是固定的无法根据实际情况选择;(2)Import导入的类只能在当前模块所依赖的下游模块中,无法导入一个上游或者第三方配置类。

但是 ImportSelector 接口可以解决上面两个缺陷,它会根据导入的 ImportSelector 实现类所返回的值作为需要导入的配置类集合,并对这些类加载。实例如下,重写 selectImports() 方法,通过获取环境变量中的配置,选择导入哪个类。

// 自定义类选择导入
@Configuration
@Import({MyImportSelector.class})
public class MyAutoConfiguration implements ImportAware {

}

public class MyImportSelector implements ImportSelector, EnvironmentAware {
    private Environment environment;

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        boolean use1 = environment.getProperty("use1", Boolean.class, false);
        String configClass = use1 ? "com.xxx.demo.extension.MyOtherConfiguration1" : "com.xxx.demo.extension.MyOtherConfiguration2";
        return new String[]{configClass};
    }

    @Override
    public void setEnvironment(Environment env) {
        environment = env;
    }
}

同样还有另外一种方式,那就是 ImportBeanDefinitionRegistrar,它的接口中直接提供了 BeanDefinitionRegistry 参数,也就意味着可以直接自主地进行 Bean注册,而不是返回一个类名或者类对象。

@Configuration
@Import({MyImportBeanDefinitionRegistry.class})
public class MyAutoConfiguratoin implements ImportAware {

}

public class MyImportBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean use1 = environment.getProperty("use1", Boolean.class, false);
        String configClass = use1 ? "com.xxx.demo.extension.MyOtherConfiguration1" : "com.xxx.demo.extension.MyOtherConfiguration2";
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(configClass);
        registry.registryBeanDefinition("myOtherConfiguration", beanDefinition);
    }
}

细看 @ImportAutoConfiguration注解

查看 ImportAutoConfiguration 注解,我们可以发现它继承了 ImportAutoConfigurationImportSelector.class 类,进入这个类源码可以发现它继承了 AutoConfigurationImportSelector 类。

AutoConfigurationImportSelector 类内部实现了 selectImports() 方法,该方法返回的全限定类名会被加载进 Bean对象池。

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

            // 核心通过这个方法获取候选类名
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
}

getCandidateConfigurations() 方法在 ImportAutoConfigurationImportSelector 类中重新实现了,代码如下:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> candidates = new ArrayList();
    Map<Class<?>, List<Annotation>> annotations = this.getAnnotations(metadata);
    annotations.forEach((source, sourceAnnotations) -> {
        this.collectCandidateConfigurations(source, sourceAnnotations, candidates);
    });
    return candidates;
}

private void collectCandidateConfigurations(Class<?> source, List<Annotation> annotations, List<String> candidates) {
    Iterator var4 = annotations.iterator();

    while(var4.hasNext()) {
        Annotation annotation = (Annotation)var4.next();
        candidates.addAll(this.getConfigurationsForAnnotation(source, annotation));
    }
}

private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {
    String[] classes = (String[])AnnotationUtils.getAnnotationAttributes(annotation, true).get("classes");
    // 如果ImportAutoConfiguration 注解指定了属性值,那么直接返回 classes的值;如果没有配置属性值,就从 spring.factories 文件中读取 key 为当前配置类名的结果
    return (Collection)(classes.length > 0 ? Arrays.asList(classes) : this.loadFactoryNames(source));
}

所以总结如下:

  1. 先获取当前配置类上的 ImportAutoConfiguration 注解信息;
  2. 如果 ImportAutoConfiguration 注解中指定了classes(或value) 属性值,那么直接返回 classes 的值;
  3. 如果未配置 classes(或value) 属性值,从 spring.factories 文件中读取key为当前配置类名的结果;

@ImportAutoConfiguration 注解使用实例

该注解的使用有以下两种方式:

方式一:直接在注解中绑定

方式二:注解中不指定,在 spring.factories 中指定

标签:重要,SpringBoot,class,注解,Import,ImportAutoConfiguration,public,configurations
From: https://www.cnblogs.com/istitches/p/18059572

相关文章

  • java 注解
    1、什么是注解      类似一种特殊的注释,可以在程序运行时被反射获取,如同标签。2、注解分类内置注解自定义注解内置注解Java定义了一套注解,共有7个,3个在java.lang中,剩下4个在java.lang.annotation中。作用在代码的注解:@Override-检查该方法是否是重......
  • SpringBoot3+Consul配置,启动后,居然不读bootstrap.yml的配置文件,直接连本地localhost:8
    问题描述如题。bootstrap.yml的配置文件: consul控制台打印的日志: 解决方案:booststrap.yml的配置文件缩进搞错了,所以压根就没有读到配置。正确的缩进:  ......
  • Spring-@Bean-注解
    1.作用用于将对象存入spring的ioc容器中。@controller、@Service、@Component、@Configuration、@Repository等几个注解是一样的,都是负责将对象存入容器当中,而@Bean是用在方法上,将当前方法的返回值对象放到容器当中。2.使用@Bean一般出现在方法上面,也可用于自定义......
  • 若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版(文末见代码
    ​ 场景若依前后端分离版本地搭建开发环境并运行项目的教程:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662 CIMGitee地址:https://gitee.com/farsunset/cimCIM项目是基于mina或者netty框架下的推送系统,我们平常使用第三方的推送SDK,如极光推送,百度......
  • Spring-@ControllerAdvice-全局处理注解
    1,@ControllerAdvice介绍@ControllerAdvice是Spring框架提供的一个注解,用于定义全局的异常处理器和全局数据绑定。它通常用于集中处理应用程序中的异常,并提供统一的异常处理逻辑。2,@ControllerAdvice的基本使用packageorg.springframework.web.bind.annotation;importj......
  • SpringBoot使用外部Web容器的解决方案
    SpringBoot默认内嵌了Web容器(如Tomcat、Jetty或Undertow),这使得应用可以作为独立的可执行JAR或WAR文件运行,无需外部Web容器。然而,在某些情况下,你可能想要将SpringBoot应用部署到外部的Web容器中,比如ApacheTomcat或Jetty。嵌入式的Web容器:应用可以打包成可执行的Jar。优点:简单......
  • 玩转SpringBoot:SpringBoot的几种定时任务实现方式
    引言在现代软件开发中,定时任务是一种常见的需求,用于执行周期性的任务或在特定的时间点执行任务。这些任务可能涉及数据同步、数据备份、报表生成、缓存刷新等方面,对系统的稳定性和可靠性有着重要的影响。SpringBoot提供了强大且简单的定时任务功能,使开发人员能够轻松地管理和执......
  • web实时消息推送方案 - (重要~个人简历要引申)
    一什么是消息推送推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用。消息推送通常是指网站的运营工作等人员,通过某种工具对用户当前网页或移动设备APP进行的主动消息推送。消息推送一般又分为Web端消息推送和移动端消息推送。......
  • 从零开始搭建Springboot开发环境(Java8+Git+Maven+MySQL+Idea)之一步到位
    说明所谓万事开头难,对于初学Java和Springboot框架的小伙伴往往会花不少时间在开发环境搭建上面。究其原因其实还是不熟悉,作为在IT界摸爬滚打数年的老司机,对于各种开发环境搭建已经了然于胸,自己当年也是这么过来的。今天我就毕其功于一役,解放大家的时间,让凡人的环境配置见鬼去吧......
  • 文件MD5校验码的安全性及重要性
    文件MD5(MessageDigestAlgorithm5)是一种常用的哈希算法,用于验证文件的完整性和安全性。本文将深入介绍文件MD5的原理、应用场景以及如何计算和验证MD5值,帮助读者更好地理解和应用这一重要工具。一、文件MD5的原理MD5算法通过对文件进行哈希运算,生成一个128位的唯一标识,......