全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-02-27_Spring中@Import原理和使用

您的位置:首页 >> 新闻 >> 行业资讯

Spring中@Import原理和使用 点击关注公众号,“技术干货”及时达! @Import注解是 Spring 框架中一个非常强大的工具,它允许你将普通类、组件类、ImportSelector实现类和ImportBeanDefinitionRegistrar实现类引入到容器中。通过@Import,你可以实现配置的模块化,使得代码更加清晰和易于维护。 Spring 集成很多框架时,就是通过 @Import 来实现的。 ?本文中源码来自 Spring 5.3.x 分支,github 源码地址:github.com/spring-proj…[1] ?一 如何使用 @Import该注解只有一个 value 属性,取值为需要导入的类的 class 对象。 有三种用法,介绍如下。 1.1 @Import 导入普通类对于普通类(「没有被声明为 Component」),通过 @Import 也可以添加到 Spring 容器中。 例如,使用 @Import(OrderService.class) ,就能向容器中添加 OrderService 类型的 bean 「。」 import com.xiakexing.service.OrderService; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(OrderService.class) public class AppConfig { } // 没有使用@Component的普通类 public class OrderService { public void test() { System.out.println("执行OrderService.test"); } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); OrderService orderService = context.getBean("orderService", OrderService.class); orderService.test(); } } 当执行上面代码时,会出现报错:No bean named 'orderService' available. 「注意,通过 @Import 直接导入的 bean,名称是该类的全类名。」 因此应这样获取 context.getBean(OrderService.class.getName(), OrderService.class) 1.2 @Import 与 ImportSelector 接口ImportSelector接口,允许你自定义条件动态选择要导入的配置类,有两个方法: selectImports:返回一个全类名的数组,这些类将被添加到 spring 容器中。注意,该方法可以返回空数组,但是不能返回 null!getExclusionFilter:返回一个 Predicate,用于排除 selectImports 方法返回值中的某些类。来看示例,OrderService 与上面相同,增加 UserService 类。 public class UserService { public void test() { System.out.println("执行UserService.test"); } } SimpleImportSelector 只导入 UserService 类。 import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; import java.util.function.Predicate; public class SimpleImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{OrderService.class.getName(), UserService.class.getName()}; } // 排除全类名中有Order的类 @Override public PredicateString getExclusionFilter() { return new PredicateString() { @Override public boolean test(String name) { return name.contains("Order"); } }; } } import com.xiakexing.service.SimpleImportSelector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(SimpleImportSelector.class) public class AppConfig { } import com.xiakexing.service.OrderService; import com.xiakexing.service.UserService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class.getName(), UserService.class); userService.test(); OrderService orderService = context.getBean(OrderService.class.getName(), OrderService.class); orderService.test(); } } 结果就是 userService.test() 执行成功,而获取 orderService 时报错。 1.3 @Import 与 ImportBeanDefinitionRegistrar 接口ImportBeanDefinitionRegistrar 接口允许通过编程方式动态注册 BeanDefinition。 来看示例,定义 User 类。 public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + " + name + ''' + ", age=" + age + '}'; } } 自定义 ImportBeanDefinitionRegistrar 接口实现,编程式向容器中注册 User 类的 beanDefinition,Spring 容器将创建对应的 bean。 import com.xiakexing.entity.User; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.AbstractBeanDefinition; 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; public class SimpleBeanRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); definition.setBeanClass(User.class); ConstructorArgumentValues values = new ConstructorArgumentValues(); values.addIndexedArgumentValue(0, "Tom"); values.addIndexedArgumentValue(1, 29); definition.setConstructorArgumentValues(values); definition.setScope("singleton"); registry.registerBeanDefinition("user", definition); } } import com.xiakexing.service.SimpleBeanRegistrar; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(SimpleBeanRegistrar.class) public class AppConfig { } 二 @Import 的原理Spring 中ConfigurationClassPostProcessor类,会扫描所有的@Configuration类,并处理其中的@Import注解。 扫描配置类:Spring 容器启动时,会扫描所有的@Configuration类。解析 @Import 注解:对于每个配置类,Spring 会解析其中的@Import注解,获取需要导入的类。处理导入的类:根据导入的类的类型(普通类、@Configuration类、ImportSelector实现类、ImportBeanDefinitionRegistrar实现类),Spring 会采取不同的处理方式。注册 BeanDefinition:最终,Spring 会将所有导入的类注册为 BeanDefinition,让 Spring 容器管理。源码中ConfigurationClassParser类负责解析@Configuration类,其中 doProcessConfigurationClass 方法逻辑如下: 先递归地收集配置类或某个注解上的 @Import 的 value 值;然后调用processImports方法来处理@Import注解,分 3 种情况处理导入的类。例如,对于 ImportBeanDefinitionRegistrar 接口实现,先收集到 Map 中缓存起来,然后遍历 Map,逐个调用 registerBeanDefinitions 方法三 源码中使用Spring 源码中,模块化、插拔式的功能选项,就是通过 @Import 实现的。如 aop、 3.1 @EnableAspectJAutoProxy 实现当在配置类上添加 @EnableAspectJAutoProxy 时,就启用了 Spring aop 功能。 「源码中,EnableAspectJAutoProxy 注解上通过 Import 引入了 AspectJAutoProxyRegistrar」,该类 ImportBeanDefinitionRegistrar 接口的实现,在 registerBeanDefinitions 方法中向容器注册了 AnnotationAwareAspectJAutoProxyCreator。 AnnotationAwareAspectJAutoProxyCreator 类是 BeanPostProcessor 接口的一个实现,会解析容器中 @Aspect 注解的 bean,封装 @Before 等方法为 Advisor 对象;在 bean 的初始化后阶段,为切面命中的 bean 创建代理对象。 3.2 @EnableAsync 实现@EnableAsync 注解提供了开箱即用的异步解决方案,我们只需在想要异步执行的方法上加 @Async 即可。 「源码中,EnableAsync 注解上通过 Import 引入了 AsyncConfigurationSelector 类,」 该类是 ImportSelector 接口实现,在 selectImports 方法中引入了 ProxyAsyncConfiguration 类(默认使用 JDK 动态代理)。在 ProxyAsyncConfiguration 中,又声明了 AsyncAnnotationBeanPostProcessor 的 bean。后者是 BeanPostProcessor 接口实现,在 bean 的初始化后阶段,为使用了 @Async 的 bean 创建代理对象。 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2021-09-05_写过小说的李诞终于来聊聊自己的本行了 下一篇:2018-12-26_MindTalk成都、重庆 | 人人都是活化城市的「都市酵母」

TAG标签:

19
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价