揭密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的東西,下文將會提到

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章