我们都知道在new出来的类中,是无法注入其他类的。因为Spring IOC的必要条件就是,要把当前类托管给Spring才行。所以我们要换个思路,如果要在我的当前类中注入其他类(使用自动注入),那么就意味着我们不能采取new的方式,而且要把当前类托管给Spring。这就引出了一系列的知识,

例如:1.如何把当前类托管给Spring ?

           2.托管了以后,不能采用new的方式,那如何获得当前类?

注:如果只是需要从Spring上下文中获取Bean的工具类,请直接看 => 第二步 编写获取Bean工具类。

下面我们用代码例子进行演示和说明。(文章最后有源代码下载链接)

当前场景:

我有一个接口,我要根据业务条件的不同,让这个接口指向不同的实现类,然后我要在这个指定的实现类中,调用我们的mybatis的mapper查询指定数据,使用@autowired将这个mapper注入当前类。

 

一、把当前要创建的类托管给Spring

 一般我们是采用@Configueration和@Bean注解来完成这件事。

@Configuration
public class AnimalsActionConfig {
    @Bean(name = "DogAction")
    public Action trusteeshipDogAction() {
        return new DogAction();
    }

    @Bean(name = "CatAction")
    public Action trusteeshipCatAction() {
        return new CatAction();
    }
}

动物行为接口代码:

public interface Action {
    /**
     * 动物行为接口
     * @param animalType 动物类型
     */
    void run(String animalType);
}

Cat实现类代码 :

public class CatAction implements Action {
    @Autowired
    private AnimalsInfoMapper animalsInfoMapper;

    @Override
    public void run(String animalType) {
        System.out.println("打印结果:" +animalsInfoMapper.getAnimalColor(animalType) + " " + animalType + " is running");
    }
}

 Dog实现类代码:

public class DogAction implements Action {
    @Autowired
    private AnimalsInfoMapper animalsInfoMapper;

    @Override
    public void run(String animalType) {
        System.out.println("打印结果:" +animalsInfoMapper.getAnimalColor(animalType) + " " + animalType + " is running");
    }
}

根据动物类型查询动物颜色Mapper代码:

public interface AnimalsInfoMapper {
    /**
     * 根据动物类型查询动物颜色
     * @param animalType 动物类型
     * @return 动物颜色
     */
    @Select(
            "select color from animal_info where type=#{animalType}"
    )
    String getAnimalColor(@Param("animalType") String animalType);
}

 

二、编写获取Bean工具类

当我们把类托管给Spring容器后,就可以通过Spring应用上下文来获取这个对象,也就是在ApplicationContext中获取对象。

@Component
public class SpringUtil implements ApplicationContextAware{
 
    private static ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }
 
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
     //根据类名获取指定对象
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }
     //根据类型获取指定对象
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }
     //根据类名和类型获取指定对象
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

三、建表语句 

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `animal_info`;
CREATE TABLE `animal_info` (
  `type` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `color` varchar(255) COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `animal_info` VALUES ('cat', 'green');
INSERT INTO `animal_info` VALUES ('dog', 'red');

四、测试

测试类代码:

@SpringBootApplication
@MapperScan("com.example.ioc.mapper")
public class IocDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(IocDemoApplication.class, args);
        //正常打印 解决了问题
        Action catAction = SpringUtil.getBean("CatAction", Action.class);
        Action dogAction = SpringUtil.getBean("DogAction", Action.class);

        //mapper出现空指针异常 产生文章头部摘要所说的问题
        /*Action catAction=new CatAction();
        Action dogAction=new DogAction();*/

        catAction.run("cat");
        dogAction.run("dog");
    }

}

打印结果:

打印结果:green cat is running
打印结果:red dog is running

 

五、结论

通过采用两种不同的获取bean的方式,得出结论,要想使用自动注入,必须先将我们的Bean托管给Spring,然后再获取。