揭密springboot自动装配(1)--ImportSelector

揭密springboot自动装配

  1. 揭密springboot自动装配(1)--ImportSelector
  2. 揭密springboot自动装配(2)--AutoConfigurationImportSelector
  3. 揭密springboot自动装配(3)--ioc及调用selectImposts
  4. 揭密springboot自动装配(4)--ioc及创建beanFactory
  5. 揭密springboot自动装配(5)--ioc及@Autowired注解

在讲这个之前,我们先来个例子热热身


首先我们先来了解下ImportSelector这个接口的应用,ImportSelector接口是spring中导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在,具体怎么用下面走个例子看看

1.实现下ImportSelector

public class UserImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{UserA.class.getName()};
    }
}

这里我们看到有个selectImports方法,我们需要实现它,返回内容我们可以看到就是个数组,把需要装配进spring容器中的bean的className放进返回数组即可

2.接着我们在启动类中添加@Import(UserImportSelector.class)

@SpringBootApplication
@Import(UserImportSelector.class)
public class DemoApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
    Object userA = run.getBeanFactory().getBean(UserA.class);
    System.out.println(userA.toString());
    Object userB = run.getBeanFactory().getBean(UserB.class);
    System.out.println(userB.toString());


  }

}

这里UserB我是没有放在selectImports中的,目的是做下对比

3.跑下我们的程序看看结果

这里你会发现UserA可以被拿到,证明已经交给spring容器中可以拿到,而UserB我没有任何处理,是拿不到的这个毫无疑问到这里肯定有人会问,直接@Import(UserA.class)不就行了,搞那么复杂,嗯,这个没错,甚至我可以跑给你们看下

@SpringBootApplication
@Import({UserImportSelector.class,UserB.class})
public class DemoApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
    Object userA = run.getBeanFactory().getBean(UserA.class);
    System.out.println(userA.toString());
    Object userB = run.getBeanFactory().getBean(UserB.class);
    System.out.println(userB.toString());
  }

}

那为什么搞那么复杂?

ImportSelector主要是实现些比较复杂有逻辑性的bean装载,我们可以在selectImports做下逻辑判断,比如@ComponentScan像这个扫描器,我们自己来写一个和它差不多的东西玩玩,起名@UserScan

1.创建注解@UserScan,引用@Import(UserImportSelector.class)

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

    @AliasFor("value")
    String[] basePackages() default {};
}

2.实现UserImportSelector 

public class UserImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(UserScan.class.getName());
        if(CollectionUtils.isEmpty(annotationAttributes))return new String[0];
        String[] basePackages = (String[]) annotationAttributes.get("basePackages");
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AssignableTypeFilter(Object.class));//这里实现包含,相当@ComponentScan  includeFilters
        //scanner.addExcludeFilter(new AssignableTypeFilter(Object.class));//这里可以实现排除,相当@ComponentScan  excludeFilters
        Set<String> classes = new HashSet<>();
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            candidateComponents.forEach(e-> {
                classes.add(e.getBeanClassName());
            });
        }
        return classes.toArray(new String[classes.size()]);
        //return new String[]{UserA.class.getName()};
    }
}

3.使用@UserScan("com.example.demo.service"),表示扫描包下的类

@SpringBootApplication
@UserScan("com.example.demo.service")
public class DemoApplication {
  public static void main(String[] args) {
    ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
    Object userA = run.getBeanFactory().getBean(UserA.class);
    System.out.println(userA.toString());
    Object userB = run.getBeanFactory().getBean(UserB.class);
    System.out.println(userB.toString());
  }
}

4.我们跑起来看看结果

这样可以看到我们是完全可以在spring容器里面拿到UserA和UserB的

好了,热身例子到这里下文将会从源码上分析springboot自动装载的实现,主要和我们前面讲的ImportSelector接口有关,其中有个叫做AutoConfigurationImportSelector的东西,下文将会提到

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值