为什么多线程、junit 中无法使用spring 依赖注入?
为什么多线程、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<User> 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就立刻变小白了。
积跬步,致千里!
为什么多线程、junit 中无法使用spring 依赖注入?的更多相关文章
- java线程中如何使用spring依赖注入
实现一个线程继承了Thread或实现Runnable接口,想在run方法中使用spring依赖注入(操作数据库),此时报错为空指针,就是说没有注入进来. 实验了几种方式,分别说一下优缺点. 1:写了工 ...
- Spring 依赖注入,在Main方法中取得Spring控制的实例
Spring依赖注入机制,在Main方法中通过读取配置文件,获取Spring注入的bean实例.这种应用在实训的时候,老师曾经说过这种方法,而且学Spring入门的时候都会先学会使用如何在普通的jav ...
- 深入浅出spring IOC中三种依赖注入方式
深入浅出spring IOC中三种依赖注入方式 spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和 ...
- 转:深入浅出spring IOC中四种依赖注入方式
转:https://blog.csdn.net/u010800201/article/details/72674420 深入浅出spring IOC中四种依赖注入方式 PS:前三种是我转载的,第四种是 ...
- Spring依赖注入的方式、类型、Bean的作用域、自动注入、在Spring配置文件中引入属性文件
1.Spring依赖注入的方式 通过set方法完成依赖注入 通过构造方法完成依赖注入 2.依赖注入的类型 基本数据类型和字符串 使用value属性 如果是指向另一个对象的引入 使用ref属性 User ...
- java后端开发三年!你还不了解Spring 依赖注入,凭什么给你涨薪
前言 前两天和一个同学吃饭的时候同学跟我说了一件事,说他公司有个做了两年的人向他提出要涨薪资,他就顺口问了一个问题关于spring依赖注入的,那个要求涨薪的同学居然被问懵了...事后回家想了想这一块确 ...
- Spring依赖注入 --- 简单使用说明
Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...
- Spring依赖注入 --- 模拟实现
Spring依赖注入 --- 模拟实现 面向接口编程,又称面向抽象编程, 数据库如果发生更改,对应的数据访问层也应该改变多写几个实现,需要用谁的时候在service里new谁就可以了面向抽象编程的好处 ...
- 二十7天 春雨滋润着无形 —Spring依赖注入
6月11日,明确."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把详细的事物加工成的形状一致的类.正是这种一致,加上合适的规范.才干彰显对象筋道的牙感和bean清 ...
随机推荐
- android在myeclipse上创建的项目各种报错
这几天被android弄得头疼死了.差不多把电脑弄了个遍. 先是离线安装ADT,下载ADT,然后配置,但是因为ADT与MyEclipse冲突.所以直接不要再myeclipse下弄Android的环境了 ...
- CSS垂直和水平居中
在css中,居中使用十分频繁. 居中分为水平和垂直居中 水平居中十分简单: body{ background:#f90; } body统一为这个颜色 div { margin:0 auto; back ...
- IE报vuex requires a Promise polyfill in this browser问题解决
使用Vuex, IE浏览器报错 因为使用了 ES6 中用来传递异步消息的的Promise,而IE低版本的浏览器不支持. ##解决方法 第一步: 安装 babel-polyfill . babel-po ...
- Linux系统优化
前言:这篇博客主机讲下安装Linux系统后调优及安全设置 基础环境 一.使用网易163镜像做yum源 默认国外的yum源速度很慢,所以换成国内的. 先备份 下载163yum源:http://mirro ...
- 清北Day4
版权声明:如需转载请标明出处,未得到本人许可请勿转载. 今天就可以看到传说中的 数据结构 嘿嘿嘿嘿 都有什么呢 链表 队列 栈 st表 hash 线段树 树链剖分 一.栈: 放出来这个看烂了的图 值得 ...
- mysql导入导出sql文件(包括数据库和数据表的操作)
废话不多说直接开始. 在windows命令行下登录mysql,创建一个test_01数据库,创建一个user表,并插入一条数据,如下 一.导出数据库test_01 1.退出数据库,在命令行中输入 my ...
- 基于python的知乎开源爬虫 zhihu_oauth使用介绍
今天在无意之中发现了一个知乎的开源爬虫,是基于Python的,名字叫zhihu_oauth,看了一下在github上面star数还挺多的,貌似文档也挺详细的,于是就稍微研究了一下.发现果然很好用啊.就 ...
- logback配置文件详解
一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...
- [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充
<Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...
- IOS(一) 基础控件的介绍以及使用
IOS的界面的制作,相对于Android来说 简洁了很多,虽然创建布局的方式都是两种(代码创建.布局文件) 但是Android中的xml布局文件在某些方面也属于代码创建,因为自己使用到得每一个属性 都 ...