博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么多线程、junit 中无法使用spring 依赖注入?
阅读量:6150 次
发布时间:2019-06-21

本文共 5790 字,大约阅读时间需要 19 分钟。

  为什么多线程、junit 中无法使用spring 依赖注入? 这个问题,其实体现了,我们对spring已依赖太深,以至于不想自己写实例了。 那么到底是为什么在多线程和junit单元测试中不能使用依赖注入呢?

一、为什么多线程下spring的依赖注入失效了呢?

  答:因为spring为了考虑安全性问题,在多线程情况下,不支持直接使用 @Resouce 注解方式进行直接的bean注入,那么也就是说,如果在多线程调用该注入实例化的变量时,将会报NullPointerException 。

  解决办法: 多线程情况下,通过调用的service进行传入需要操作的bean变量,而多线程只是将前台工作转移到后台。如下:

# CalculateServiceImpl.java 服务实现,传入需要调用的bean
package com.xx.op.user;        import com.xx.note.dubbo.dto.CertificateApplyDto;    import com.xx.con.dubbo.api.ContractRemoteService;    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;        import org.slf4j.Logger;    import org.slf4j.LoggerFactory;        import javax.annotation.Resource;        public class CalculateServiceImpl implements CalculateService {            private Logger logger = LoggerFactory.getLogger(this.getClass());                @Resource(name = "threadPoolTaskExecutor")        private ThreadPoolTaskExecutor threadPoolTaskExecutor;                @Resource                // 默认name可写可不写        private ContractRemoteService contractRemoteService;                @Override        public void doSth(String userId) throws Exception            CertificateApplyDto certificateApplyDto = new CertificateApplyDto();            certificateApplyDto.setBorrowNid(userId);            SignContractThread signContractThread = new SignContractThread(contractRemoteService, certificateApplyDto);            threadPoolTaskExecutor.execute(signContractThread);                //异步签署协议        }    }

# SignContractThread.java 异步实现调用

package com.xx.cc.common.async;    import com.alibaba.fastjson.JSON;    import com.dianping.cat.message.Event;    import com.xx.framework.dto.ResponseEntity;    import com.xx.no.dubbo.dto.CertificateApplyDto;    import com.xx.con.dubbo.api.ContractRemoteService;    import org.slf4j.Logger;    import org.slf4j.LoggerFactory;    public class SignContractThread implements Runnable {        private Logger logger = LoggerFactory.getLogger(this.getClass());        /**         * 无法使用依赖注入实现多纯种的bean, 从外部传入方式         */        private ContractRemoteService contractRemoteService;        private CertificateApplyDto certificateApplyDto;        public SignContractThread(ContractRemoteService contractRemoteService, CertificateApplyDto certificateApplyDto) {            this.contractRemoteService = contractRemoteService;            this.certificateApplyDto = certificateApplyDto;        }        @Override        public void run() {            String requestParamJson = JSON.toJSONString(this.doSSt);            logger.debug("===========>>>>> 异步调用, 参数: {} ==============>>>>>>>>>", requestParamJson);            try {                ResponseEntity responseEntity = contractRemoteService.doSSt(certificateApplyDto);                logger.debug("<<<<<<<<<<=========== 异步调用,method:doSSt,返回结果:{}", responseEntity);                EE.logEvent("Monitor_signContract", "asyncSignContractResult", Event.SUCCESS, JSON.toJSONString(responseEntity));            } catch (Exception e) {                logger.error("==-------===异步调用,发生异常,请求参数: {}, 异常-{}", requestParamJson, e););                throw new RuntimeException("异步调用_doSSt,发生异常", e);            } finally {                // ... 调用完毕            }        }    }

  这样,通过传入外部依赖注入的bean,线程进行调用,即可避免线程无法注入bean的问题了。当然了,你可能还会想到使用 getBean的方法获取,其实也是可以的,不过应该有一定的危险性,因为相当于你得再次将applicationContext里的东西再实例化一遍。

二、junit中无法使用依赖注入的问题?

  答:因为junit一般会走最小化的方式,而非每次都要将整个框架的东西载入,从而减少加载时间。当然,如果确实需要,这个问题,其实目前在高版本的junit中,已经不存在了,通过加载 SpringJUnit4ClassRunner,即可进行注入值。

  解决方案1:使用高版本的junit进行测试,如下:

package com.xx.mybatis3spring3intg.junit;    import java.util.List;    import com.xx.mybatis3spring.bean.User;    import com.xx.mybatis3spring.service.UserService;        import org.junit.Test;    import org.junit.runner.RunWith;    import org.springframework.beans.factory.annotation.Autowired;    import org.springframework.test.context.ContextConfiguration;    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;        @RunWith(SpringJUnit4ClassRunner.class)    @ContextConfiguration({
"/config/application*.xml"}) public class UserServiceTest { @Resource private UserService userService; @Test public void c1() { List
userList = userService.query(new User()); System.out.println(userList); } }

  解决方案2:通过getBean的方式获取需要的bean,因为仅仅是单元测试,加载资源稍微多些也没有关系。

package com.xx.c.order;    import org.junit.Test;    import org.springframework.context.ApplicationContext;    import org.springframework.context.support.ClassPathXmlApplicationCoimport com.xx.c.service.order.OrderService;    public class OrderServiceTest {        private static ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");        private static OrderService orderService = (OrderService)context.getBean("orderService");        private static Object getBean(String name) {            if (context == null) {                context = new ClassPathXmlApplicationContext("applicationContext.xml");            }            return context.getBean(name);        }        public static void main(String[] args) {            String borrowNid = "11111111111";            com.xx.c.dubboapi.biz.OutApiManager service = (com.xx.c.dubboapi.biz.OutApiManager)getBean("outApiManagerImpl");            System.out.println("========"+service.getWang(borrowNid));            System.out.println("========"+service.getRepayList("111111111111111111"));       }        }

 

  以上,就基本解决了如题所问,当然也可以作为所有无法注入bean的问题的解决方案。信不信由你,反正我是信了。 

  注意的几点就是:

      1, 多线程的执行,面向C端的用户,一定不能直接 new Thread() 进行多线程操作,否则会死得很惨。

    2,多做好日志记录,在出错的时候进行排查真的很方便,但也得做日志的清理工作,否则服务器空间被占满也不是很长时间的事。

      3,单元测试还是有必要做的,否则提交测试时,自己哪来的底气呢。

      4,多了解spring核心的东西,做到知其然知其所以然,不要脱离spring就立刻变小白了。

  积跬步,致千里!

转载地址:http://cbmya.baihongyu.com/

你可能感兴趣的文章
Extjs4.1.x 框架搭建 采用Application动态按需加载MVC各模块
查看>>
Silverlight 如何手动打包xap
查看>>
建筑电气暖通给排水协作流程
查看>>
JavaScript面向对象编程深入分析(2)
查看>>
linux 编码转换
查看>>
POJ-2287 Tian Ji -- The Horse Racing 贪心规则在动态规划中的应用 Or 纯贪心
查看>>
Windows8/Silverlight/WPF/WP7/HTML5周学习导读(1月7日-1月14日)
查看>>
关于C#导出 文本文件
查看>>
使用native 查询时,对特殊字符的处理。
查看>>
maclean liu的oracle学习经历--长篇连载
查看>>
ECSHOP调用指定分类的文章列表
查看>>
分享:动态库的链接和链接选项-L,-rpath-link,-rpath
查看>>
Javascript一些小细节
查看>>
禁用ViewState
查看>>
Android图片压缩(质量压缩和尺寸压缩)
查看>>
nilfs (a continuent snapshot file system) used with PostgreSQL
查看>>
【SICP练习】150 练习4.6
查看>>
HTTP缓存应用
查看>>
KubeEdge向左,K3S向右
查看>>
DTCC2013:基于网络监听数据库安全审计
查看>>