spring的bean在多线程中注入的问题

本文介绍在Spring框架中如何解决异步线程中Bean注入为null的问题,并提供了一个利用ApplicationContextAware接口来手动获取Bean的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

在spring中,如果需要在异步线程中注入bean,会发现bean是空的情况。原因据说是spring bean 出于线程安全考虑,不得注入bean至线程类(Runnable)。
代码如下:

public class DealThreadTask implements Runnable{



    @Autowired
    private DealService dealService;


    @Override
    public void run() {

    //  DealService dealService=holder.getBean("dealService");
        System.out.println("dealService-->"+dealService);
        dealService.deal("andy", "李琳", 100d);


    }

}

在controller层中,对上述的service进行调用。


    public static void main(String[] args){

        ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/applicationContext-aware.xml");
         DealThreadTask task=new DealThreadTask();
         new Thread(task).start();

    }

运行结果:

dealService-->null
Exception in thread "Thread-1" java.lang.NullPointerException
    at com.test.spring.tx.multi.DealThreadTask.run(DealThreadTask.java:38)
    at java.lang.Thread.run(Thread.java:744)

说明spring在DealThreadTask中未能将dealService注入进去。

解决方法

Spring API 中有ApplicationContextAware 这个接口,实现了这个接口的类,可以在容器初始化完成中获得容器,从而可以获得容器中所有的bean。

public class ApplicationContextHolder implements ApplicationContextAware {

     private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext=applicationContext;
        System.out.println("applicationContext---->"+applicationContext);
    }

     public static <T> T getBean(Class<T> clazz){
         return applicationContext.getBean(clazz);
   }

     public static <T> T getBean(String name) {

         if (applicationContext==null) {
             System.out.println("applicationContext为空");
        }
            return (T) applicationContext.getBean(name);

     }
}

然后,在xml配置文件中,需要将这个类配置进去。

<bean id="applicationContextHolder"  class="com.test.spring.tx.multi.ApplicationContextHolder"></bean>

这样,在异步线程中的DealThreadTask 中,通过手动的applicationContextHolder的getBean方法,就可以获取所需要的bean。

public class DealThreadTask implements Runnable{



    @Autowired
    private ApplicationContextHolder holder;



    @Override
    public void run() {

        DealService dealService=holder.getBean("dealService");
        System.out.println("dealService-->"+dealService);
        dealService.deal("andy", "李琳", 100d);


    }

}

提示

上述的代码中


    public static void main(String[] args){

        ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/applicationContext-aware.xml");
         DealThreadTask task=new DealThreadTask();
         new Thread(task).start();

    }

用了main方法,而没有用junit的test注解进行测试,是因为junit是不会等待异步线程执行完然后结束,而是junit自己本线程的代码执行完就结束了。由于代码中设计到数据库操作,因此如果简单的用junit进行测试,可能的结果是测试完成,但是数据库操作还没有进行。如果一定要用junit进行测试,可以用其他的手段,比如thread的join操作,或者在junit的测试方法中等待键盘输入才结束,这些都是为了让异步线程执行完后才结束junit测试。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值