简介

用过Spring都晓得想注入一个Bean很简略!

@ResourceCustomBean customBean;

大略像这样就能够注入一个曾经存在容器里的Bean,但前提是你把这个Bean退出容器、退出也很简略,只有在类的下面@Component,@Service等等一些框架提供的注解就能够!

当初 咱们要本人写一个组件,咱们要本人治理咱们的组件,应用本人的注解管本人的Bean。

这时候ImportBeanDefinitionRegistrar就退场了!

基本功

step1

咱们也有模有样的起个Enable结尾的启动注解、

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(ImportCustomBeanDefinitionRegistrar.class)//联合@Import注解,这里参可参考其余Blogpublic @interface EnableCustomBean {}

step2

而后把这个注解放到启动类上,平时都是看大佬们Enable这样用,今个儿我本人也能开发个!

@SpringBootApplication@EnableCustomBeanpublic class BootApplication {    public static void main(String[] args) {        SpringApplication.run(BootApplication.class, args);    }}

step3

再自定义一个Bean,

public class CustomBean {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "CustomBean{" +                "name='" + name + '\'' +                '}';    }}

好了,看起来所有很完满呢,只有把CustomBean这个类注册到容器就OK!

step4

怎么把CustomBean退出容器呢?尽管说咱们是本人定义的类,但还是运行在Spring里,有一些初始工作还是要Spring帮咱们一把。这里实现ImportBeanDefinitionRegistrar接口,明天的角儿!办法registerBeanDefinitions在Spring启动的时候会运行到!在博客@Import里有解释。

public class ImportCustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {    @Override    public void registerBeanDefinitions(AnnotationMetadata im  portingClassMetadata, BeanDefinitionRegistry registry) {        //到这里就很明确了,        String simpleName = CustomBean.class.getName();        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();        rootBeanDefinition.setBeanClass(CustomBean.class);        MutablePropertyValues propertyValues = new MutablePropertyValues();        propertyValues.add("name", "Savey");        rootBeanDefinition.setPropertyValues(propertyValues);        registry.registerBeanDefinition(simpleName, rootBeanDefinition);    }}

step5

跑个Test看下吧

@SpringBootTestpublic class ImportBeanDefinitionRegistrarTest {        //只管注入即可,    @Resource    CustomBean bean;//    @Resource    ApplicationContext applicationContext;    @Test    public void test_register_custom_bean() {        System.out.println(bean);    }}

不出意外的话打印出CustomBean{name='Savey'},阐明咱们CustomBean曾经被加载到容器里了!

进阶

咱们要求把某个包下的类都加到容器、另外呢,我还要加一个自定义注解,只有在这个包下加了自定义注解的能力被加到容器!

其实,有了下面的基本功,想实现上面这个性能就太简略多了!

step1

自定义个注解

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documentedpublic @interface Savey {}

step2

EnableCustomBean注解里加个属性嘛、

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(ImportCustomBeanDefinitionRegistrar.class)public @interface EnableCustomBean {    /**     * 定义要扫描的包     */    String[] basePackages() default {};}

step3

批改启动类、

@SpringBootApplication@EnableCustomBean(basePackages = {"com.boot.boot.savey"})public class BootApplication {    public static void main(String[] args) {        SpringApplication.run(BootApplication.class, args);    }}

这里我传递一个basePackages属性,让指定包下的类才退出容器!!

step4

创立com.boot.boot.savey目录,在目录下创立一些要自定义Bean,
留神: 给类加上 Savey注解!!

@Savey@Getter@Setter@ToStringpublic class Money {}@Savey@Getter@Setter@ToStringpublic class Work {}//这个类就不加Savey注解了,不想它退出到容器,不想玩游戏,只想工作!所以不加了!@Getter@Setter@ToStringpublic class PlayGame {}

step5

批改ImportCustomBeanDefinitionRegistrar

@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    //获取EnableCustoBean正文的属性    final Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableCustomBean.class.getName());    //获取包扫描    ClassPathScanningCandidateComponentProvider pathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false);    //增加过滤 带有Savey这个注解的类    pathScanningCandidateComponentProvider.addIncludeFilter(new AnnotationTypeFilter(Savey.class));    LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();    for (String basePackages : (String[]) attributes.get("basePackages")) {        candidateComponents.addAll(pathScanningCandidateComponentProvider.findCandidateComponents(basePackages));    }        //注册Bean    for (BeanDefinition candidateComponent : candidateComponents) {        registry.registerBeanDefinition(candidateComponent.getBeanClassName(), candidateComponent);    }}

打个Test吧

@SpringBootTestpublic class ImportCustomScanPackagesDefinitionRegisterTest {    @Resource    ApplicationContext applicationContext;    @Test    public void test_scan_packages() {        Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);    }}

最初只有它俩退出了容器,PlayGame却没有!

com.boot.boot.savey.Moneycom.boot.boot.savey.Work

代码在GitHub