广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot中@Import注解如何正确使用
  • 539
分享到

SpringBoot中@Import注解如何正确使用

2024-04-02 19:04:59 539人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录简介一、功能简介二、示例1.引入普通类2.引入ImportSelector的实现类(1)静态import场景(注入已知的类)(2)动态import场景(注入指定条件的类

简介

由于最近的项目需求,需要在把配置类导入到容器中,通过查询,使用@Import注解就能实现这个功能,@Import注解能够帮我们吧普通配置类(定义为Bean的类)导入到ioc容器中。该注解我们也能过在源码中经常看到,是框架层实现的重要注解。下面是我对@import注解的使用做的简单的总结。希望能够帮助各位,同时如果有问题的话,也恳请各位提出宝贵的意见。

一、功能简介

引入普通类 引入配置类(@Configuration注解修饰的)

引入ImportSelector的实现类

  • 静态import场景(注入已知的类)
  • 动态import场景(注入指定条件的类)

引入ImportBeanDefinitionRegister的实现类

二、示例

1.引入普通类

@Import类引入普通的类可以帮我们把普通的类定义为Bean

@Import可以添加在@SpringBootApplication(启动类)、@Configuration(配置类)、@Component(组件类)对应的类上。

注意:@RestController、@Service、@Repository都属于@Component

// 通过@Import注解把普通添加到IOC容器里面去
@Import(ImportAnnotationTest.class)
@springBootApplication
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoApplication.class, args);
        ImportAnnotationTest bean = context.getBean(ImportAnnotationTest.class);
        context.close();
    }
}

引入配置类(@Configuration注解修饰的)

@Import除了可以把普通的类定义为Bean,@Import还可以引入一个@Configuration修饰的类(引入配置类),从而把让配置类生效(配置类下的所有Bean添加到IOC容器里面去)。在自定义starter的时候经常会用到。

如果配置类在标准的SpringBoot包结构下(SpringBootApplication启动类包的根目录下)。是不需要@Import导入配置类的,SpringBoot自动帮做了。

springboot项目会默认将启动类同目录及其子目录下的组件扫描到ioc容器当中去,无需手动扫描。

上面的情况一般用于@Configuration配置类不在标准的SpringBoot包结构下面。所以一般在自定义starter的时候用到。

@Configuration(proxyBeanMethods = false)
@Import({  // import了两个哈
        XXXDataConfiguration.XXXPartOneConfiguration.class,
        XXXDataConfiguration.XXXPartTwoConfiguration.class
})
public class XXXDataAutoConfiguration {
}
public class XXXDataConfiguration {
    @Configuration(proxyBeanMethods = false)
    static class XXXPartOneConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public BeanForIoc beanForIoc() {
            return new BeanForIoc();
        }
    }
    @Configuration(proxyBeanMethods = false)
    static class XXXPartTwoConfiguration {
        
    }
}

2.引入ImportSelector的实现类

@Import还可以引入ImportSelector的实现类,把ImportSelector接口selectImports()方法返回的Class名称都定义为bean。

注意selectImports()方法的参数AnnotationMetadata,通过这个参数我们可以获取到@Import标注的Class的各种信息。这一点特别有用,用于做一些参数的传递。在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在。

public interface ImportSelector {
    
    String[] selectImports(AnnotationMetadata importinGClaSSMetadata);
}

用例如下:

@Configuration
@Import(value = {Person.class,MyImportSelector.class})
public class MyBeanDefinitionRegister {
}

配置类中导入实现了ImportSelector 的类

实现了ImportSelector接口的类

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.example.importannotation.importSelector.Dog","com.example.importannotation.importSelector.Cat"};
    }
}

(1)静态import场景(注入已知的类)


public class XXXConfigurationSelector implements ImportSelector {
    @Override
    @NonNull
    public String[] selectImports(@NonNull AnnotationMetadata importingClassMetadata) {
        // 把XXX对应的类,定义为Bean
        return new String[]{XXX.class.getName()};
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(XXXConfigurationSelector.class)
public @interface EnableXXX {
}
@SpringBootApplication
@EnableXXX // 使之生效
public class mybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyBatisApplication.class, args);
    }
}

(2)动态import场景(注入指定条件的类)

我们做一个这样的功能,我们需要把指定包路径下所有实现了HelloService接口的类做为bean添加到IOC容器里面去。@ComponentScan注解用来帮我们指定路径。具体实现如下:

@Configuration
@ComponentScan("com.example.importannotation") // 指定路径
@Import(DynamicSelectImport.class)
public class DynamicSelectConfig {
}

动态实现将实现某个接口的实现类加载到容器中

public class DynamicSelectImport implements ImportSelector {
    
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 第一步:获取到通过ComponentScan指定的包路径
        String[] basePackages = null;
        // @Import注解对应的类上的ComponentScan注解
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            Map<String, Object> annotationAttributes = importingClassMetadata
                    .getAnnotationAttributes(ComponentScan.class.getName());
            basePackages = (String[]) annotationAttributes.get("basePackages");
        }
        if (basePackages == null || basePackages.length == 0) {
            //ComponentScan的basePackages默认为空数组
            String basePackage = null;
            try {
                // @Import注解对应的类的包名
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            basePackages = new String[]{basePackage};
        }
        // 第2步,知道指定包路径下所有实现了HelloService接口的类
        // (ClassPathScanningCandidateComponentProvider的使用)
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        TypeFilter helloServiceFilter = new AssignableTypeFilter(HelloService.class);
        scanner.addIncludeFilter(helloServiceFilter);
        Set<String> classes = new HashSet<>();
        for (String basePackage : basePackages) {
            scanner.findCandidateComponents(basePackage)
                    .forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
        }
        // 第三步,返回添加到IOC容器里面去
        return classes.toArray(new String[0]);
    }
}

接口

public interface HelloService {
    void function();
}

接口的实现类

public class DemoaClass implements HelloService{
    @Override
    public void function() {
    }
}
public class DemobClass implements HelloService{
    @Override
    public void function() {
    }
}

测试结果如下,两个实现类都加入到了IOC容器当中

3.引入ImportBeanDefinitionRegister的实现类

@Import引入ImportBeanDefinitionRegistrar的实现类。一般用来动态注册bean。最重要的一点是还可以对这些BeanDefinition进行额外的修改或增强。咱们经常使用的mybatis @MapperScan就是用这种方式实现的。

ImportBeanDefinitionRegistrar,我们一般会实现ImportBeanDefinitionRegistrar类,然后配合一个自定义的注解一起使用。而且在注解类上@Import我们的这个实现类。

通过自定义注解的配置,拿到注解的一些元数据。然后在ImportBeanDefinitionRegistrar的实现类里面做相应的逻辑处理,比如把自定义注解标记的类添加到Spring IOC容器里面去。


public interface ImportBeanDefinitionRegistrar {
    
    void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

关于@Import引入ImportBeanDefinitionRegistrar的使用强烈建议大家去看看mybatis关于@MapperScan的处理源码。特别有意思。我们也举一个非常简单的实例,来让大家直观的看到ImportBeanDefinitionRegistrar的使用,比如我们想把指定包路径下所有添加了BeaNIOc注解的类注册为bean。具体实现如下:


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface BeanIoc {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(BeanIocScannerRegister.class)
public @interface BeanIocScan {
    String[] basePackages() default "";
}

public class BeanIocScannerRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    private final static String PACKAGE_NAME_KEY = "basePackages";
    private ResourceLoader resourceLoader;
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //1. 从BeanIocScan注解获取到我们要搜索的包路径
        AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(BeanIocScan.class.getName()));
        if (annoAttrs == null || annoAttrs.isEmpty()) {
            return;
        }
        String[] basePackages = (String[]) annoAttrs.get(PACKAGE_NAME_KEY);
        // 2. 找到指定包路径下所有添加了BeanIoc注解的类,并且把这些类添加到IOC容器里面去
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry, false);
        scanner.setResourceLoader(resourceLoader);
        scanner.addIncludeFilter(new AnnotationTypeFilter(BeanIoc.class));
        scanner.scan(basePackages);
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}

@Configuration
@BeanIocScan(basePackages = "com.tuacy.collect.mybatis")
public class BeanIocScanConfig {
}

下面是一个具体的实现:

@Data
public class Car {
    private String id;
    private String name;
}
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition catDef = new RootBeanDefinition(Cat.class);
        RootBeanDefinition carDef = new RootBeanDefinition(Car.class);
        registry.registerBeanDefinition("cat", catDef);
        registry.registerBeanDefinition("car", carDef);
    }
}
@Configuration
@Import(value = {Person.class, MyBeanDefinitionRegister.class})
public class MyImportBeanDefinitionRegistrarConfig {
}

今天的@Import注解就讲解完了

到此这篇关于SpringBoot中@Import注解如何正确使用的文章就介绍到这了,更多相关SpringBoot @Import内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringBoot中@Import注解如何正确使用

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

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

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

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

下载Word文档
猜你喜欢
  • SpringBoot中@Import注解如何正确使用
    目录简介一、功能简介二、示例1.引入普通类2.引入ImportSelector的实现类(1)静态import场景(注入已知的类)(2)动态import场景(注入指定条件的类...
    99+
    2022-11-13
  • SpringBoot中@Import注解的使用方式
    目录一、 @Import引入普通类二、 @Import引入配置类(@Configuration修饰的类)三 、@Import引入ImportSelector的实现类3.1 ...
    99+
    2022-11-13
  • SpringBoot中的@Import注解怎么使用
    这篇文章主要介绍了SpringBoot中的@Import注解怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot中的@Import注解怎么使用文章都会有所收获,下面我们一起来看看吧。一、 ...
    99+
    2023-06-30
  • 如何正确使用注解
    本篇内容介绍了“如何正确使用注解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!日志脱敏场景简介在日志里我们的日志一般打印的是 model 的...
    99+
    2023-06-16
  • SpringBoot@Import与@Conditional注解使用详解
    目录@Import@Conditional说明:基于atguigu学习笔记。 在了解spring boot自动配置原理前,再来了解下两个注解@Import注解和@Conditiona...
    99+
    2022-11-13
    SpringBoot @Import注解 SpringBoot @Conditional注解
  • 如何正确的使用@SpringBootApplication注解
    如何正确的使用@SpringBootApplication注解?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。对SpringBoot工程的自动配置很感兴趣,于是学习其源码并整...
    99+
    2023-06-14
  • 如何在Java中正确的使用注解
    如何在Java中正确的使用注解?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。注解是jdk1.5新增的特性.大家都知道,jdk1.5在java的发展史上有着划时代的意义.而注...
    99+
    2023-05-31
    java 注解 ava
  • springboot中redis正确的使用详解
    redis实现了对数据的缓存,在项目里一些字典数据,会话数据,临时性数据都会向redis来存储,而在springboot里对redis也有支持,一般来说多个线程共同使用一个redis...
    99+
    2022-11-13
  • 利用SpringBoot进行Web开发时如何正确的使用注解
    利用SpringBoot进行Web开发时如何正确的使用注解?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、spring-boot-starter-web 依赖...
    99+
    2023-05-31
    springboot web
  • springboot中的redis怎么正确使用
    这篇“springboot中的redis怎么正确使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springboot中的r...
    99+
    2023-06-30
  • 如何正确的使用Springboot配置文件
    这篇文章给大家介绍如何正确的使用Springboot配置文件,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。如果使用IDEA创建Springboot项目,默认会在resource目录下创建application.prop...
    99+
    2023-05-31
    springboot bo
  • 如何正确的使用SpringBoot AOP 拦截器
    本篇文章给大家分享的是有关如何正确的使用SpringBoot AOP 拦截器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。常用用于实现拦截的有:Filter、HandlerIn...
    99+
    2023-05-31
    springboot aop 拦截器
  • 如何正确使用Python中的函数注释
    本篇内容主要讲解“如何正确使用Python中的函数注释”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何正确使用Python中的函数注释”吧!我在查看python的fixture源码时发现 fi...
    99+
    2023-06-15
  • springboot中@component注解如何使用
    这篇文章主要介绍“springboot中@component注解如何使用”,在日常操作中,相信很多人在springboot中@component注解如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”spr...
    99+
    2023-06-29
  • 如何正确规范使用论文脚注
    论文中的脚注有很多种,根据不同学校的要求来定,这个需要涉及到Word的使用,很多同学不会使用Word,我这里说的不会使用,不是指不会打开Word输入文字,而是里面的许多功能我们先讲一下什么是脚注。脚注,是汉语词汇,汉语拼音为就是可以附在文章...
    99+
    2023-06-03
  • Python中print如何正确使用
    Python中print如何正确使用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python print会对输出的文本做自动的编码转换,而文件对象的write方法就不会做,因...
    99+
    2023-06-17
  • 如何正确使用Android线程详解
    前言 对于移动开发者来说,“将耗时的任务放到子线程去执行,以保证UI线程的流畅性”是线程编程的第一金科玉律,但这条铁则往往也是UI线程不怎么流畅的主因。我们在督促自己更多的使用...
    99+
    2022-06-06
    android线程 Android
  • 如何正确使用WideCharToMultiByte
    要正确使用WideCharToMultiByte函数,需要按照以下步骤操作:1. 确定要转换的宽字符编码方式。WideCharToM...
    99+
    2023-09-26
    使用
  • 如何正确使用MVCC
    这篇文章主要讲解了“如何正确使用MVCC”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何正确使用MVCC”吧! 简单理解版以下先引用我之前写过的...
    99+
    2022-10-19
  • 如何正确使用@property
    本篇内容主要讲解“如何正确使用@property”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何正确使用@property”吧!他们是这样说的:class People: ...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作