highlight: androidstudio

我们知道注册bean到IOC中有很多中方式,比如xml方式 ,JavaConfig方式 包括:(@Compent,@Service,@Controller,@Repository,@Bean)等等。 但是除了以上几种,有没有其他方式把我们的对象交给IOC让他去管理呢?\ 答案肯定是有啦!!! 那就是@Import();

@Import支持三种类型的导入。

1) 普通类 2) 配置类(如 Configuration修饰的类) 3) 实现了 ImportSelector(可以选择性导入到IOC)接口 4) 实现了 ImportBeanDefinitionRegistrar 接口 (可以添加bean定义信息到spring中(使用RootBeanDefinition的registerBeanDefinition方法),从而被spring创建bean并管理)`

下边我们分别举例并测试一下~~~

1. 导入普通类到IOC容器

我们来试一把 (注意 ImportJavaConfigList中的@Configuration被我注掉了) image.png

哎嗨报错了。加上@Configuration我们再看看

image.png

ok没问题,普通的类EmailService可以注册到spring容器中了。


2. 导入配置类(Configuration修饰的类)到IOC容器

image.png

如图,可以看到RedisTemplateExamplespring 管理,有人说我不@Import也行呀,spring也会扫描到RedisConfigurationExample配置类从而创建bean呀,这里我想说的是,其实我觉得@Import中的参数即xxx.class更多是在非springboot启动类项目中的配置类,举个例子: 假如我有个admin服务(是个springboot项目),然后admin需要依赖commonpom文件,common是非springboot应用,这个时候,其实你可以指定扫描路径扫描到common中的xxx.class配置类(比如@scan("com.xzll.*")),也可以使用这种@Import的方式导入该xxx.class

3. 导入实现了ImportSelector接口的类到IOC容器

  • 这里模拟一个场景就是(根据注解值的不同,来使用不同的bean来进行报警消息发送)
3.1 定义一个注解 EnableAlarmNotice

java /** * @Author: hzz * @Date: 2021/9/18 16:33:34 * @Description: 加载springboot启动类上 用于指定开启哪些报警方式 */ @Retention(RetentionPolicy.RUNTIME) @Documented @Target(ElementType.TYPE) @Import(AlarmServiceSelector.class) public @interface EnableAlarmNotice { String[] types() default {"ding_ding"}; }

3.2 自定义个选择器 (根据上边注解的types获取不同的bean) 实现 ImportSelector

```java /** * @Author: hzz * @Date: 2021/9/18 17:01:08 * @Description: 报警方式选择器 根据EnableAlarmNotice注解中的types字段来进行选择性注入bean */ public class AlarmServiceSelector implements ImportSelector {

@Override public String[] selectImports(AnnotationMetadata annotationMetadata) {

//获取注解上的type,然后根据types数组选择性的创建bean 放到IOC中
  Map<String, Object> map = annotationMetadata.getAnnotationAttributes(EnableAlarmNotice.class.getName(), true);
  List<String> needInIOCBean = new ArrayList<>();
  if (map != null && !map.isEmpty()) {
     String[] types = (String[]) map.get("types");
     if (Objects.isNull(types) || types.length == 0)
        return new String[0];

     for (int i = 0; i < types.length; i++) {
        needInIOCBean.add(AlarmNoticeTypeEnum.getClassFullName(types[i]));
     }
  }
  return needInIOCBean.toArray(new String[0]);

} } ```

3.3 搞个枚举 来定义报警的方式以及bean的全类名

```java @Getter @AllArgsConstructor @NoArgsConstructor public enum AlarmNoticeTypeEnum {

EMAIL("email", "com.xzll.common.alarm.service.impl.EmailAlarmNoticeImpl"), DINGDING("dingding", "com.xzll.common.alarm.service.impl.DingDingAlarmNoticeImpl");

private String type; private String classFullName;

public static String getClassFullName(String type) { AlarmNoticeTypeEnum[] var1 = values(); int var2 = var1.length;

for (int var3 = 0; var3 < var2; ++var3) {
     AlarmNoticeTypeEnum alarmNoticeTypeEnum = var1[var3];
     if (Objects.equals(alarmNoticeTypeEnum.type, type)) {
        return alarmNoticeTypeEnum.getClassFullName();
     }
  }
  return StringUtils.EMPTY;

} } ```

3.4 在启动类开启注解并设置ding_ding和email两个值

```java @SpringBootTest(classes = StudyTestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) @RunWith(SpringJUnit4ClassRunner.class) @EnableRabbitMq @EnableAlarmNotice( types= {"ding_ding", "email"}) @Slf4j public class StudyTestApplicationTest {

} ```

3.5 执行单元测试看下结果

image.png

但是我发现 用@Service注册的bean和实现ImportSelector注册的bean的id不一样,这个在实际中要注意下 如下所示:

image.png

ok关于 ImportSelector就说到这


4. 导入实现了ImportBeanDefinitionRegistrar 接口的类到IOC容器

4.1 我们实现ImportBeanDefinitionRegistrar接口,并重写其方法,然后再该方法中,可以对bean信息进行修改或者增加。

如下所示:

image.png

ok关于@Import注解今天就说这些了,有时间整理一篇其源码文章。相信会对这个注解有更深刻的理解。大后天中秋节,祝大家中秋快乐!!!


Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐