Spring注解驱动开发 第五节 Import注册bean到spring容器

Spring注解驱动开发 第五节 Import注册bean到spring容器

spring注册bean的方式有许多种,我们尝试了许多种方式,现在要实验一下新的注册方式,使用@Import注解注册一个bean到spring容器中。

public class Color {
}

首先创建一个空类,我们的任务就是要把这个Color类注册到Spring容器中。

@Configuration
@Import(Color.class)
public class MainConfig {

}

这个是主配置类,我们用了@Import注解注入了一个Color对象

 @Test
    public void test001(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for(String name : names){
            System.out.println(name);
        }
    }

运行测试类打印结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
com.meng.Color

Process finished with exit code 0

由此可以看出,Color类被注册到spring容器中,所以@Import也是可以实现bean的注入的,但是需要注意Import注解也是可以接收一个数组参数的,所以在import里可以传入一个数组集合。

Import选择器

除了使用@Import注解,还可以使用选择器来将对象注入到spring容器。

public class MyImportSelector implements ImportSelector {
    /**
     * 返回值表示返回要注入类的全类名,可以为空字符串数组,但是不能为null,否则会发生异常
     * AnnotationMetadata 他表示当前标注@Import注解的全部注解信息(也就表示不只是有import,还有其他的注解都可以获取到)
     * @param importingClassMetadata
     * @return
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        return new String[]{"com.meng.pojo.Color"};
    }
}

上图是import的选择器,自定义一个类并且实现ImportSelector接口,重写接口中的方法,返回要注入的类名称叫Color类。

@Configuration
@Import({MyImportSelector.class})
public class MainConfig3 {

}

在配置类中加入import注解,把刚才的import选择器作为import的参数,就可以使用这个选择器。打印结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig3
com.meng.pojo.Color

Process finished with exit code 0

Color被注入到spring中。
加一个断点再次分析重写方法的参数获取到的是什么
在这里插入图片描述
在选择器中加入一个断点,然后查看AnnotationMetadata中的内容。
在这里插入图片描述
可以看出,importingClassMetadata参数里有一个annotation属性,里面有两个注解,一个是Configuration,一个是我们自定义的MyImportSelector选择器,所以正好验证了上面代码的注释,可以获取@Import标志的所有注解信息。
当我们在选择器中返回null的时候,进行实验

public class MyImportSelector implements ImportSelector {
    /**
     * 返回值表示返回要注入类的全类名,可以为空字符串数组,但是不能为null,否则会发生异常
     * AnnotationMetadata 他表示当前标注@Import注解的全部注解信息(也就表示不只是有import,还有其他的注解都可以获取到)
     * @param importingClassMetadata
     * @return
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        return null;
    }
}

打印结果:

四月 23, 2019 10:26:48 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@105fece7: startup date [Tue Apr 23 10:26:48 GMT+08:00 2019]; root of context hierarchy
四月 23, 2019 10:26:48 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.meng.config.MainConfig3]; nested exception is java.lang.NullPointerException

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.meng.config.MainConfig3]; nested exception is java.lang.NullPointerException

	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:616)
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:299)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:198)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
	at MainStart.<init>(MainStart.java:14)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
	at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NullPointerException
	at org.springframework.context.annotation.ConfigurationClassParser.asSourceClasses(ConfigurationClassParser.java:673)
	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:587)
	... 33 more


Process finished with exit code -1

抛出异常了,是一个空指针异常,现在让我们来追踪一下,为什么返回null会抛出异常。
在这里插入图片描述
当我们查看源码,在运行完选择器返回的时候进入如下代码块,也就是要运行红色箭头所指的方法,我们继续点击这个方法,追究原因。
在这里插入图片描述
当她把参数.length的时候,由于我们返回的是null,所以造成了空指针异常。所以(注意!注意!注意!)千万不要在ImportSelector选择器中返回null,要返回空字符串数组。

最后我们要通过ImportBeanDefinitionRegistrar的方式注册bean,废话不多说直接上代码。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * AnnotationMetadata 当前类的注解信息,以及所有注解。
     * BeanDefinitionRegistry  BeanDefinition注册类
     * 把所需要添加到容器中的bean;调用
     * registry.registerBeanDefinition();注册进来。
     * @param importingClassMetadata
     * @param registry
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        if(cb(registry,"com.meng.pojo.black") && cb(registry,"com.meng.pojo.Blue")){
            registry.registerBeanDefinition("red",new RootBeanDefinition(Red.class));
        }
    }

    public boolean cb(BeanDefinitionRegistry registry,String path){
        return  registry.containsBeanDefinition(path);
    }
}

上面的代码要实现一个ImportBeanDefinitionRegistrar 接口并重写方法,方法的作用在代码中有详细的介绍。这个逻辑主要是在spring容器中是否发现名称为com.meng.pojo.black和com.meng.pojo.Blue的组件,有的话就注册red类到spring容器中,在注入的时候需要注意第一个参数表示组件的名称,第二个参数要接受一个实现了BeanDefinition接口的实现类,而RootBeanDefinition实现了它,所以把类传给RootBeanDefinition构造器,然后再给注入方法。
打印结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig3
com.meng.pojo.black
com.meng.pojo.Blue
com.meng.pojo.Color
com.meng.pojo.yellow
red

Process finished with exit code 0

可以看到red类被成功注入到spring容器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值