Spring Framework 组件注册 之 @Import

简介: @Import注解可以将@configuration 类、importSelector和importBeanDefinitionRegistrar实现类,以及普通的javaBean类注册到spring容器中。

Spring Framework 组件注册 之 @Import

写在前面

向spring中注册组件或者叫javaBean是使用spring的功能的前提条件。而且spring也提供了很多种方式,让我们可以将普通的javaBean注册到spring容器中,比如前一篇文章Spring Framework 组件注册 之 @Component中写的利用@Component注解将普通的javaBean注册到容器中,本文说的@Import注解也是spring Framework提供的将普通javaBean注册到容器中,以及后续文章会说的@Configuration,FactoryBean等方式。

@Import 注册普通Bean

使用@Import注册一个普通Bean,只需要在@Import注解中指定待注册Bean的class即可

/**
 * 使用Import注解,注册一个普通的Bean
 */
@Data
public class TestImport {
    private String id = "@Import";
}

在spring启动引导类中,添加@Import注解

/**
 * spring 容器启动引导类
 */
@Import(TestImport.class)
public class TestImportBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestImportBootstrap.class);
        System.out.println("context id : " + applicationContext.getId());
        String[] beanNames = applicationContext.getBeanNamesForType(TestImport.class);
        System.out.println("Bean Name is : " + Arrays.toString(beanNames));
        TestImport bean = applicationContext.getBean(TestImport.class);
        System.out.println("TestImport bean : " + bean);
        applicationContext.close();
    }
}

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c

==Bean Name is : [com.spring.study.ioc.register.TestImport]==
TestImport bean : TestImport(id=@Import)

通过简单使用@Import注解,便可以将一个普通的javaBean注册到spring容器中。并且我们可以看到,通过@Import注解默认注册的组件名称为该javaBean的全类名

@Import 导入 配置类

使用@Import注解导入配置类,就会将配置类中的所有组件注册到spring容器中。在spring中,并不是@Configuration标注的类才是配置类,但是被@Configuration标注的类会被生成代理对象,spring注入时与不使用@Configuration注解有很大区别,后续会单独说明此处内容,本文不在赘述。

/**
 * spring组件配置类
 */
//@Configuration 使用@Import导入时,此注解可以不加
public class TestConfiguration {
    @Bean
    public TestImport testImport() {
        return new TestImport();
    }

    @Bean
    public TestImport testImport2() {
        return new TestImport();
    }
}

@Import注解中指定待导入的配置类

/**
 * spring 容器启动引导类
 */
@Import(TestConfiguration.class)
public class TestImportBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestImportBootstrap.class);
        System.out.println("context id : " + applicationContext.getId());
        String[] beanNames = applicationContext.getBeanNamesForType(TestImport.class);
        System.out.println("Bean Name is : " + Arrays.toString(beanNames));
        TestImport bean = (TestImport) applicationContext.getBean("testImport");
        System.out.println("TestImport bean : " + bean);
        applicationContext.close();
    }
}

spring容器启动后,配置类中的注解同样会被注册到spring容器中:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@21b8d17c

==Bean Name is : [testImport, testImport2]==
TestImport bean : TestImport(id=@Import)

由结果可以看出,此时注册的组件名称即为配置类中指定的组件名称,并且通过配置类,可以一次导入多个组件。

@Import 通过ImportSelector 注册

ImportSelector接口中只定义了一个接口selectImports,通过此接口返回需要注册的JavaBean的全类名数组,在使用@Import导入时,会将接口返回的所有类注册到spring容器中

/**
 * 通过 ImportSelector 接口注册组件
 */
@Data
public class TestSelector {
    private String id = "@Import:ImportSelector";
}

自定义实现ImportSelector接口

/**
 * 自定义组件选择器,通过返回需要注册的bean的全类名,进行快速的在IOC容器中注册组件
 */
public class CustomImportSelector implements ImportSelector {

    /**
     * @param importingClassMetadata 标注了@Import配置类上面所有的注解信息
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{TestSelector.class.getName()};
    }
}

@Import注解中指定ImportSelector实现类

/**
 * spring 容器启动引导类
 */
@Import(CustomImportSelector.class)
public class TestImportBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestImportBootstrap.class);
        System.out.println("context id : " + applicationContext.getId());
        TestSelector bean = applicationContext.getBean(TestSelector.class);
        System.out.println("TestSelector bean : " + bean);
        String[] beanNames = applicationContext.getBeanNamesForType(TestSelector.class);
        System.out.println("bean names:" + Arrays.asList(beanNames));
        applicationContext.close();
    }
}

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81

TestSelector bean : ==TestSelector(id=@Import:ImportSelector)==
bean names:[==com.spring.study.ioc.register.TestSelector==]

由结果可以看出,TestSelector被注册到了spring容器中。与前面的直接注册相比,并没有看出ImportSelector接口的突出特性。本文只是简单的说明ImportSelector接口具有注册组件的功能,对于spring容器在启动时,如何执行BeanDefinitionRegistryPostProcessor来调用selectImports方法;如何使用ImportSelector接口实现更复杂的注册功能,将在后续文章中深入理解。

@Import 通过ImportBeanDefinitionRegistrar 注册

ImportBeanDefinitionRegistrar接口中只定义了一个registerBeanDefinitions方法,在此方法中,可以获取到BeanDefinitionRegistry对象,利用此对象,即可手动将需要的组件注册的spring容器中。在使用BeanDefinitionRegistry对象时,还可以指定组件在spring容器中注册的bean名称。

/**
 * 通过 ImportBeanDefinitionRegistrar 接口手动注册组件
 */
@Data
public class TestRegistrar {
    private String id = "@Import:TestRegistrar";
}

自定义实现ImportBeanDefinitionRegistrar接口

/**
 * 手动注册组件到IOC容器中
 */
public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * @param importingClassMetadata 标注了@Import配置类上面所有的注解信息
     * @param registry               BeanDefinition注册器,可以通过此registry手动的向容器中注册指定的组件
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        if (!registry.containsBeanDefinition("testRegistrar")) {
            BeanDefinition definition = new RootBeanDefinition(TestRegistrar.class);
            registry.registerBeanDefinition("testRegistrar", definition);
        }
    }
}

@Import注解中指定ImportBeanDefinitionRegistrar实现类

/**
 * spring 容器启动引导类
 */
@Import(CustomImportBeanDefinitionRegistrar.class)
public class TestImportBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestImportBootstrap.class);
        System.out.println("context id : " + applicationContext.getId());
        TestRegistrar bean = applicationContext.getBean(TestRegistrar.class);
        System.out.println("TestRegistrar bean : " + bean);
        String[] beanNames = applicationContext.getBeanNamesForType(TestSelector.class);
        System.out.println("bean names:" + Arrays.asList(beanNames));
        applicationContext.close();
    }
}

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81

TestRegistrar bean : ==TestRegistrar(id=@Import:TestRegistrar)==
bean names:==[testRegistrar]==

由此可以看出,TestRegistrar被注册到了spring容器中。与ImportSelector接口一样,在spring容器启动时,通过BeanDefinitionRegistryPostProcessor来执行接口方法。

@Import同时指定多种接口注册

上面的例子中分别说明了使用@Import,通过直接导入Bean class,配置类,ImportSelector接口,ImportBeanDefinitionRegistrar接口来向spring容器中注册组件。当然在使用@Import注解时,可以同时指定上面的任意几种方式进行注册

/**
 * spring 容器启动引导类
 *
 * @author TangFD
 * @since 2019/6/25.
 */
@Import({
        TestComponent.class,
        TestConfiguration.class,
        CustomImportSelector.class,
        CustomImportBeanDefinitionRegistrar.class
})
public class TestImportBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestImportBootstrap.class);
        System.out.println("context id : " + applicationContext.getId());
        String[] beanNames = applicationContext.getBeanDefinitionNames();
        System.out.println("bean names:" + Arrays.asList(beanNames));
        applicationContext.close();
    }
}

spring容器启动后,控制台打印的结果:

context id : org.springframework.context.annotation.AnnotationConfigApplicationContext@238e0d81

==bean names:==[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, ==testImportBootstrap, com.spring.study.ioc.register.TestComponent, com.spring.study.ioc.register.TestConfiguration, testImport, testImport2, com.spring.study.ioc.register.TestSelector, testRegistrar==]

总结

向spring容器中注册组件的方式有很多,本文主要说明了如何使用@Import注解向spring容器中注册组件。并且遗留了一个需要深入理解的知识点:在spring容器启动时,如何通过执行BeanDefinitionRegistryPostProcessor来执行ImportSelectorImportBeanDefinitionRegistrar接口方法进行组件注册。此处内容,将在后续的spring容器启动过程中,分析BeanFactoryPostProcessor接口执行过程里进行补充。

学习永远都不是一件简单的事情,可以有迷茫,可以懒惰,但是前进的脚步永远都不能停止。

不积跬步,无以至千里;不积小流,无以成江海;

相关文章
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1275 4
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
477 0
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
428 0
|
8月前
|
XML Java 测试技术
使用 Spring 的 @Import 和 @ImportResource 注解构建模块化应用程序
本文介绍了Spring框架中的两个重要注解`@Import`和`@ImportResource`,它们在模块化开发中起着关键作用。文章详细分析了这两个注解的功能、使用场景及最佳实践,帮助开发者构建更清晰、可维护和可扩展的Java应用程序。
372 0
|
10月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
949 0
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
1389 61
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
12994 4
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
277 10

热门文章

最新文章