解决SpringBoot2多线程无法注入的问题
1、情况描述
使用springboot2多线程,线程类无法实现自动注入需要的bean,解决思路,通过工具类获取需要的bean
如下
package com.ps.uzkefu.apps.ctilink.handler; import com.baomidou.mybatisplus.mapper.entitywrapper; import com.ps.uzkefu.apps.callcenter.entity.callrecord; import com.ps.uzkefu.apps.callcenter.service.callrecordservice; import com.ps.uzkefu.apps.ctilink.init.applicationcontextprovider; import com.ps.uzkefu.apps.ctilink.ommodel.callcdr; import com.ps.uzkefu.apps.ctilink.ommodel.cdr; import com.ps.uzkefu.apps.ctilink.rediskey.cdrtype; import com.ps.uzkefu.apps.ctilink.rediskey.eventtype; import com.ps.uzkefu.apps.ctilink.rediskey.rediskeyprefix; import com.ps.uzkefu.apps.oms.account.entity.user; import com.ps.uzkefu.apps.oms.account.service.userservice; import com.ps.uzkefu.util.uuidutil; import com.ps.uzkefu.utils.phonemodel; import com.ps.uzkefu.utils.phoneutils; import org.apache.commons.lang.stringutils; import org.redisson.api.rbucket; import org.redisson.api.redissonclient; import java.util.date; import java.util.objects; /** * author:zhushangjin * date:2018/6/26 */ public class cdrhandler implements runnable { public cdr cdr; //无法自动注入 public redissonclient redissonclient; //无法自动注入 public userservice userservice; //无法自动注入 public callrecordservice callrecordservice; public cdrhandler() { //new的时候注入需要的bean this.redissonclient = applicationcontextprovider.getbean(redissonclient.class); this.userservice = applicationcontextprovider.getbean(userservice.class); this.callrecordservice = applicationcontextprovider.getbean(callrecordservice.class); } public redissonclient getredissonclient() { return redissonclient; } public void setredissonclient(redissonclient redissonclient) { this.redissonclient = redissonclient; } public cdr getcdr() { return cdr; } public void setcdr(cdr cdr) { this.cdr = cdr; } public userservice getuserservice() { return userservice; } public void setuserservice(userservice userservice) { this.userservice = userservice; } public callrecordservice getcallrecordservice() { return callrecordservice; } public void setcallrecordservice(callrecordservice callrecordservice) { this.callrecordservice = callrecordservice; } @override public void run() { if (this.getcdr().getouter() != null) { saveoutercdr(); } else if (this.getcdr().getvisitor() != null) { savevistorcdr(); } } private void saveoutercdr() { // 外呼 通话结束 callcdr callcdr = null; rbucket<callcdr> bucket = redissonclient.getbucket(rediskeyprefix.call_outer_cdr + this.getcdr().getouter().getid() + "_" + cdr.getcpn()); callcdr = bucket.get(); callcdr.setrediskey(rediskeyprefix.call_outer_cdr + this.getcdr().getouter().getid() + "_" + cdr.getcpn()); callcdr.setlastevent(eventtype.bye); callcdr.setlasteventtime(new date()); callcdr.settalklength(integer.parseint(this.getcdr().getduration())); callcdr.settrunknum(this.getcdr().gettrunknumber()); callcdr.sethanguptime(new date()); callcdr.setrecord(this.getcdr().getrecording()); if (callcdr.getansweredtime() == null){ callcdr.setcalltime(callcdr.gethanguptime()); }else { long time = callcdr.getansweredtime().gettime() - callcdr.getringlength()*1000; callcdr.setcalltime(new date(time)); } //todo 保存到数据库 user user = userservice.selectone(new entitywrapper<user>().eq("extension", callcdr.getextensionnum() + "")); callcdr.setusername(user.getusername()); callcdr.setcorpcode(user.getcorpcode()); callcdr.setcreater(user.getid()); callcdr.setid(uuidutil.genuuid()); callcdr.setcreatetime(new date()); phonemodel phonemodel = phoneutils.getphonemodel(callcdr.getcustomerphone()); if (phonemodel != null) { callcdr.setcustomercity(phonemodel.getcityname()); callcdr.setcustomerprovince(phonemodel.getprovincename()); } callcdr.setcallid(system.currenttimemillis() + "" + callcdr.getcallid()); bucket.set(callcdr); callrecord callrecord = callcdr; boolean result = callrecordservice.insert(callrecord); if (result) { bucket.delete(); } } private void savevistorcdr() { callcdr callcdr = null; rbucket<callcdr> bucket = redissonclient.getbucket(rediskeyprefix.call_visitor_cdr + this.getcdr().getvisitor().getid() + "_" + cdr.gettrunknumber()); callcdr = bucket.get(); callcdr.setrediskey(rediskeyprefix.call_visitor_cdr + this.getcdr().getvisitor().getid() + "_" + cdr.gettrunknumber()); callcdr.setrecord(this.getcdr().getrecording()); phonemodel phonemodel = phoneutils.getphonemodel(callcdr.getcustomerphone()); if (phonemodel != null) { callcdr.setcustomercity(phonemodel.getcityname()); callcdr.setcustomerprovince(phonemodel.getprovincename()); } callcdr.setcallid(system.currenttimemillis() + "" + callcdr.getcallid()); callcdr.setid(uuidutil.genuuid()); //来电 通话结束 外部电话 呼入 接入分机的童虎记录 if (objects.equals(cdrtype.in, this.getcdr().gettype()) && this.getcdr().getcdpn().length() == 5) { callcdr.setextensionnum(integer.parseint(this.getcdr().getcdpn())); user user = userservice.selectone(new entitywrapper<user>().eq("extension", callcdr.getextensionnum() + "")); callcdr.setusername(user.getusername()); callcdr.setcorpcode(user.getcorpcode()); callcdr.setcreater(user.getid()); if (objects.equals(eventtype.ring, callcdr.getlastevent())) { if (stringutils.isblank(this.getcdr().getrecording())) { //用户在坐席未接来电时 未接来电无录音 挂机 int ringlength = (int) ((new date().gettime() - callcdr.getlasteventtime().gettime()) / 1000); callcdr.setringlength(ringlength); callcdr.settalklength(0); } else { //特殊情况 坐席接听后立马挂掉 callcdr.settalklength(integer.parseint(this.getcdr().getduration())); callcdr.setringlength(-1); callcdr.setlastevent(cdrtype.unusual); } } else { //正常情况 callcdr.settalklength(integer.parseint(this.getcdr().getduration())); } } else if (objects.equals(cdrtype.in, this.getcdr().gettype()) && this.getcdr().getcdpn().length() != 5) { //客服没接到 callcdr.setextensionnum(0); callcdr.setusername("未接到"); callcdr.setcorpcode(this.getcdr().getcdpn()); callcdr.setcreater("未接到"); callcdr.settalklength(0); int ringlength = (int) ((new date().gettime() - callcdr.getcalltime().gettime())/1000); callcdr.setringlength(ringlength); } callcdr.setcreatetime(new date()); callcdr.sethanguptime(new date()); bucket.set(callcdr); if (objects.equals(cdrtype.in, this.getcdr().gettype()) && this.getcdr().getcdpn().length() == 5 && objects.equals(eventtype.ring, callcdr.getlastevent()) && stringutils.isnotblank(this.cdr.getrecording())) { }else if(objects.equals(cdrtype.unusual,callcdr.getlastevent())){ }else { callrecord callrecord = callcdr; boolean result = callrecordservice.insert(callrecord); if (result) { bucket.delete(); } } } }
2、获取bean的工具类
package com.ps.uzkefu.apps.ctilink.init; import org.springframework.beans.beansexception; import org.springframework.context.applicationcontext; import org.springframework.context.applicationcontextaware; import org.springframework.stereotype.component; /** * author:zhushangjin * date:2018/7/3 */ @component public class applicationcontextprovider implements applicationcontextaware { /** * 上下文对象实例 */ private static applicationcontext applicationcontext; @override public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception { this.applicationcontext = applicationcontext; } /** * 获取applicationcontext * * @return */ public static applicationcontext getapplicationcontext() { return applicationcontext; } /** * 通过name获取 bean. * * @param name * @return */ public static object getbean(string name) { return getapplicationcontext().getbean(name); } /** * 通过class获取bean. * * @param clazz * @param <t> * @return */ public static <t> t getbean(class<t> clazz) { return getapplicationcontext().getbean(clazz); } /** * 通过name,以及clazz返回指定的bean * * @param name * @param clazz * @param <t> * @return */ public static <t> t getbean(string name, class<t> clazz) { return getapplicationcontext().getbean(name, clazz); } }
3、通过工具类的getbean方法即可获取bean
补充知识:关于spring/springboot在静态工具类中注入service的解决方案
前言今天博主将为大家分享:关于spring/springboot在静态工具类中注入service的解决方案!不喜勿喷,如有异议欢迎讨论!
最近遇到了需要在工具类中注入service,由于工具类中方法一般都是静态的,所以要求该属性也要是静态的(service)。但是由于spring/springboot正常情况下不能支持注入静态属性(会报空指针异常)。主要原因在于:spring的依赖注入实际上是依赖于set方法进行注入值的,spring是基于对象层面的依赖注入,而静态属性/静态变量实际上是属于类的。
解决方案:
给当前的工具类加上@component,使其成为一个bean对象
声明一个静态的属性(加上注解@autowired),一个非静态的属性。
声明一个返回值为void并且不能抛出异常的方法,在其中将非静态属性赋值给静态属性。该方法上加上注解@postconstruct
这样就将service的值注入了进来。示例代码如下:
/** * *@description: 关于spring/springboot在静态工具类中注入service的解决方案 *@classname: xxutils.java *@author chenyongjia *@date 2019年6月26日 晚上21:20 *@email chen87647213@163.com */ @component public class xxutils { @autowired private speciallogsevice sevice; private static speciallogsevice speciallogsevice; @postconstruct public void init() { speciallogsevice = sevice; } //下面的内容就省略了,需要调用speciallogsevice打点就行了 }
在上述代码中@postconstruct是java ee5规范之后,servlet新增的两个影响servlet声明周期的注解之一,另外一个是@preconstruct。这两个都可以用来修饰一个非静态的返回值为void的方法,并且该方法不能抛出异常。
被@postconstruct注解修饰的方法会在服务器加载servlet的时候运行,并且只会被服务器调用一次,类似于servlet中的init方法。被该注解修饰的方法会在构造器执行之后,init方法执行之前执行。spring中允许开发者在受理的bean中去使用它,当ioc容器被实例化管理当前bean时,被该注解修饰的方法会执行,完成一些初始化的工作。
被preconstruct注解修饰的方法会在服务器卸载servlet的时候运行,类似于servlet中的destroy方法。被该注解修饰的方法会在destroy方法执行之后,servlet彻底卸载之前执行。
到这里:关于spring/springboot在静态工具类中注入service的解决方案!分享完毕了,快去试试吧!希望大家多多支持!
推荐阅读
-
VMware Workstation 无法恢复错误: (vcpu-0) 问题的解决方法
-
微信小程序实现Session功能及无法获取session问题的解决方法
-
android支付宝客户端html5网页无法自动关闭问题的解决方法
-
Asp.Net服务器发送HTTP标头后无法设置内容类型的问题解决
-
PDO取Oracle lob大字段,当数据量太大无法取出的问题的解决办法
-
SQLServer 数据库变成单个用户后无法访问问题的解决方法
-
Windows 64 位 mysql 5.7以上版本包解压中没有data目录和my-default.ini及服务无法启动的快速解决办法(问题小结)
-
无法启动Apache的问题解决方法
-
IIS无法显示中文名称图片问题的解决方法
-
C盘整理碎片时无法移动某些文件的问题解决办法介绍