SpringBoot自动装配-Import

1. 简介

@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:

  1. 导入Bean

  2. 导入配置类

  3. 导入 ImportSelector 实现类。一般用于加载配置文件中的类

  4. 导入 ImportBeanDefinitionRegistrar 实现类。

2. 定义

@Import注解定义如下,其内部只有一个参数为Class对象数组

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { Class<?>[] value(); }

3. 使用说明

通过一个简单的小例子测试一下@Import是不是真的能实现Bean的注入

3.1 创建项目

3.1.1 导入依赖

这里我们除了springboot依赖,再添加个lombok依赖

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ldx</groupId> <artifactId>import-annotation</artifactId> <version>0.0.1-SNAPSHOT</version> <name>import-annotation</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>

3.1.2 创建User类

package com.ldx.importannotation; import lombok.AllArgsConstructor; import lombok.Data; /** * 用户信息实体 * @author ludangxin * @date 2021/8/1 */ @Data @AllArgsConstructor public class User { public User() { this.name = "李四"; this.age = 13; } private String name; private Integer age; }

3.2 测试导入Bean

3.2.1 修改启动类

import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; @Slf4j // 注入UserBean @Import(value = User.class) @SpringBootApplication public class ImportAnnotationApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ImportAnnotationApplication.class, args); User user = applicationContext.getBean(User.class); log.info("user info ==={}",user); } }

3.2.2 启动测试

UserBean注入成功。

. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.3) 2021-08-01 19:36:55.243 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : Starting ImportAnnotationApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 49498 (/Users/ludangxin/workspace/idea/import-annotation/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/import-annotation) 2021-08-01 19:36:55.245 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : No active profile set, falling back to default profiles: default 2021-08-01 19:36:55.731 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : Started ImportAnnotationApplication in 0.893 seconds (JVM running for 1.417) 2021-08-01 19:36:55.735 INFO 49498 --- [ main] c.l.i.ImportAnnotationApplication : user info ===User(name=李四, age=13)

3.3 测试导入配置类

3.3.1 创建UserConfig类

import org.springframework.context.annotation.Bean; /** * 用户配置类 * @author ludangxin * @date 2021/8/1 */ public class UserConfig { @Bean public User getUser(){ return new User(); } }

3.3.2 修改启动类

将启动类上的@Import的value指向UserConfig

@Import(value = UserConfig.class)

3.3.3 启动测试

UserBean注入成功。

3.4 测试导入ImportSelector

3.4.1 创建UseImportSelector类

import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; /** * 用户Bean选择器配置类 * @author ludangxin * @date 2021/8/1 */ public class UseImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 指定User类的全限类名 return new String[]{"com.ldx.importannotation.User"}; } }

3.4.2 修改启动类

将启动类上的@Import的value指向UseImportSelector

@Import(value = UseImportSelector.class)

3.4.3 启动测试

UserBean注入成功。

3.5 测试导入ImportBeanDefinitionRegistrar类

3.5.1 创建UserImportBeanDefinitionRegistrar

package com.ldx.importannotation; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; /** * 用户Bean定义注册配置类 * @author ludangxin * @date 2021/8/1 */ public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 创建User类型的Bean的定义 BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); // 将创建的UserBean定义注册到SpringRegistry中,其名称为user registry.registerBeanDefinition("user", beanDefinition); } }

3.5.2 修改启动类

将启动类上的@Import的value指向UserImportBeanDefinitionRegistrar

@Import(value = UserImportBeanDefinitionRegistrar.class)

3.5.3 启动测试

UserBean注入成功。

3.6 小结

简介中介绍的四种方式都可以注入UserBean。

好处:

  1. 导入指定的Bean或配置类。例如:由于业务需要将包路径或者需要加载的Bean类不在@ComponentScan的扫描范围内,这时候我们就可以通过@Import来实现Bean的注入。
  2. ImportSelector方式是制定需要加载类的全限类名。这时候我们就可以将我们的需要装载的类写到配置文件中,比如某个txt中,然后项目启动的时候读取txt中的全限类名,实现Bean的装载。SpringBoot就是使用这种方式实现的自动装配。

4. 改进

上面的例子通过使用@Import注解实现了spring bean的自动注入。但是装载Bean每次都得指定Bean的类或者配置类,在生产环境中我们在使用第三方Jar的时候根本不知道应该使用哪个配置文件或者压根就不知道配置文件的名称。这时我们其实可以扩展一个注解来优化这个问题。

4.1 创建注解

package com.ldx.importannotation; import org.springframework.context.annotation.Import; import java.lang.annotation.*; /** * 启用User配置信息注解 * @author ludangxin * @date 2021/8/1 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented // 指定需要导入的UserBean的配置类 @Import(UseImportSelector.class) public @interface EnableUser {}

4.2 修改启动类

注掉之前的@Import,使用刚创建的@EnableUser注解

import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; @Slf4j //@Import(value = UserImportBeanDefinitionRegistrar.class) @EnableUser @SpringBootApplication public class ImportAnnotationApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ImportAnnotationApplication.class, args); User user = applicationContext.getBean(User.class); log.info("user info ==={}",user); } }

4.3 启动测试

UserBean注入成功。

思考🤔

SpringBoot项目中能不能直接获取或者使用Jar包中的Bean呢?

5. 验证

5.1 创建项目

user模块为Bean的提供者,book-manage通过引入user模块Jar,来验证项目中能不能直接使用Jar中的Bean

5.2 创建user模块

5.2.1 导入依赖

没啥特别的依赖

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ldx</groupId> <artifactId>user</artifactId> <version>0.0.1-SNAPSHOT</version> <name>user</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>

5.2.2 创建User类

package com.ldx.user; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; /** * 用户信息类 * @author ludangxin * @date 2021/8/1 */ @Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String name; /** * 角色状态吗 1.管理员 2.老师 3.学生 */ private Character role; private Integer age; public User getUserInfo() { return new User(66, "张三", '3', 21); } /** * 获取其任课老师信息 */ public List<User> getTeachers() { List<User> users = new ArrayList<>(); User user = new User(); user.setId(2); user.setName("王麻子"); user.setAge(45); user.setRole('2'); User user1 = new User(); user1.setId(3); user1.setName("李四"); user1.setAge(35); user1.setRole('2'); users.add(user); users.add(user1); return users; } }

5.2.3 修改启动类

import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @Slf4j @SpringBootApplication public class UserApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(UserApplication.class, args); User user = applicationContext.getBean(User.class); user.getTeachers().forEach(obj -> log.info("user teacher info ==={} ", obj) ); } @Bean public User getUser() { return new User(); } }

5.2.4 启动测试

在user模块中先验证下User Bean注册的正确性,log如下:

. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.3) 2021-08-01 21:09:54.666 INFO 51037 --- [ main] com.ldx.user.UserApplication : Starting UserApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51037 (/Users/ludangxin/workspace/idea/verifyusejarbean/user/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean) 2021-08-01 21:09:54.669 INFO 51037 --- [ main] com.ldx.user.UserApplication : No active profile set, falling back to default profiles: default 2021-08-01 21:09:55.151 INFO 51037 --- [ main] com.ldx.user.UserApplication : Started UserApplication in 0.818 seconds (JVM running for 1.317) 2021-08-01 21:09:55.155 INFO 51037 --- [ main] com.ldx.user.UserApplication : user teacher info ===User(id=2, name=王麻子, role=2, age=45) 2021-08-01 21:09:55.156 INFO 51037 --- [ main] com.ldx.user.UserApplication : user teacher info ===User(id=3, name=李四, role=2, age=35)

user bean 注册成功。

5.2.5 装载Jar

点击idea maven插件的install将jar装载到本地仓库

5.3 创建book-manage模块

5.3.1 导入依赖

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ldx</groupId> <artifactId>book-manage</artifactId> <version>0.0.1-SNAPSHOT</version> <name>book-manage</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- user模块依赖 --> <dependency> <groupId>com.ldx</groupId> <artifactId>user</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>

5.3.2 修改启动类

直接获取User Bean 并调用getUserInfo方法

import com.ldx.user.User; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @Slf4j @SpringBootApplication public class BookManageApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(BookManageApplication.class, args); User user = applicationContext.getBean(User.class); log.info("user info === {}", user.getUserInfo()); } }

5.3.3 启动测试

启动报错,没有可用的User Bean

. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.3) 2021-08-01 21:15:09.219 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : Starting BookManageApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51124 (/Users/ludangxin/workspace/idea/verifyusejarbean/book-manage/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean) 2021-08-01 21:15:09.221 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : No active profile set, falling back to default profiles: default 2021-08-01 21:15:09.623 INFO 51124 --- [ main] c.ldx.bookmanage.BookManageApplication : Started BookManageApplication in 0.707 seconds (JVM running for 1.133) Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ldx.user.User' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) at com.ldx.bookmanage.BookManageApplication.main(BookManageApplication.java:15)

6. 改进

在5.0章节中我们验证了直接使用jar包中的bean时不可取的,那有什么办法能解决么?

这时候我们就可以使用4.0中的Enable注解来解决这个问题。

6.1 在user模块中添加Enable注解

import org.springframework.context.annotation.Import; import java.lang.annotation.*; /** * 启用User配置信息注解 * @author ludangxin * @date 2021/8/1 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(User.class) public @interface EnableUser {}

6.2 修改book-manage模块中的启动类

book-manage模块的启动类上加上@EnableUser注解

6.3 启动验证

user bean 注入成功。

. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.3) 2021-08-01 21:18:55.686 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : Starting BookManageApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 51193 (/Users/ludangxin/workspace/idea/verifyusejarbean/book-manage/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/verifyusejarbean) 2021-08-01 21:18:55.688 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : No active profile set, falling back to default profiles: default 2021-08-01 21:18:56.145 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : Started BookManageApplication in 0.762 seconds (JVM running for 1.223) 2021-08-01 21:18:56.148 INFO 51193 --- [ main] c.ldx.bookmanage.BookManageApplication : user info === User(id=66, name=张三, role=3, age=21)

7. 小结

  1. 不能直接在当前项目中使用Jar中的Bean(SpringBoot默认使用ImportSelector的方式加载META-INF/spring.factories中指定的配置类,会导致只需要导入相应的第三方Jar就可以使用其环境中的Bean)
  2. 可以在当前项目中使用Jar包中提供的Enable注解来导入Jar的Bean配置

__EOF__

本文作者张铁牛
本文链接https://www.cnblogs.com/ludangxin/p/15087565.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   张铁牛  阅读(414)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
点击右上角即可分享
微信分享提示