解决SpringBoot2多线程无法注入的问题
1、情况描述
使用springboot2多线程,线程类无法实现自动注入需要的bean,解决思路,通过工具类获取需要的bean
如下
packagecom.ps.uzkefu.apps.ctilink.handler; importcom.baomidou.mybatisplus.mapper.EntityWrapper; importcom.ps.uzkefu.apps.callcenter.entity.CallRecord; importcom.ps.uzkefu.apps.callcenter.service.CallRecordService; importcom.ps.uzkefu.apps.ctilink.init.ApplicationContextProvider; importcom.ps.uzkefu.apps.ctilink.ommodel.CallCdr; importcom.ps.uzkefu.apps.ctilink.ommodel.Cdr; importcom.ps.uzkefu.apps.ctilink.rediskey.CdrType; importcom.ps.uzkefu.apps.ctilink.rediskey.EventType; importcom.ps.uzkefu.apps.ctilink.rediskey.RedisKeyPrefix; importcom.ps.uzkefu.apps.oms.account.entity.User; importcom.ps.uzkefu.apps.oms.account.service.UserService; importcom.ps.uzkefu.util.UUIDUtil; importcom.ps.uzkefu.utils.PhoneModel; importcom.ps.uzkefu.utils.PhoneUtils; importorg.apache.commons.lang.StringUtils; importorg.redisson.api.RBucket; importorg.redisson.api.RedissonClient; importjava.util.Date; importjava.util.Objects; /** *Author:ZhuShangJin *Date:2018/6/26 */ publicclassCdrHandlerimplementsRunnable{ publicCdrcdr; //无法自动注入 publicRedissonClientredissonClient; //无法自动注入 publicUserServiceuserService; //无法自动注入 publicCallRecordServicecallRecordService; publicCdrHandler(){ //new的时候注入需要的bean this.redissonClient=ApplicationContextProvider.getBean(RedissonClient.class); this.userService=ApplicationContextProvider.getBean(UserService.class); this.callRecordService=ApplicationContextProvider.getBean(CallRecordService.class); } publicRedissonClientgetRedissonClient(){ returnredissonClient; } publicvoidsetRedissonClient(RedissonClientredissonClient){ this.redissonClient=redissonClient; } publicCdrgetCdr(){ returncdr; } publicvoidsetCdr(Cdrcdr){ this.cdr=cdr; } publicUserServicegetUserService(){ returnuserService; } publicvoidsetUserService(UserServiceuserService){ this.userService=userService; } publicCallRecordServicegetCallRecordService(){ returncallRecordService; } publicvoidsetCallRecordService(CallRecordServicecallRecordService){ this.callRecordService=callRecordService; } @Override publicvoidrun(){ if(this.getCdr().getOuter()!=null){ saveOuterCdr(); }elseif(this.getCdr().getVisitor()!=null){ saveVistorCdr(); } } privatevoidsaveOuterCdr(){ //外呼通话结束 CallCdrcallCdr=null; RBucketbucket=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(newDate()); callCdr.setTalkLength(Integer.parseInt(this.getCdr().getDuration())); callCdr.setTrunkNum(this.getCdr().getTrunkNumber()); callCdr.setHangupTime(newDate()); callCdr.setRecord(this.getCdr().getRecording()); if(callCdr.getAnsweredTime()==null){ callCdr.setCallTime(callCdr.getHangupTime()); }else{ longtime=callCdr.getAnsweredTime().getTime()-callCdr.getRingLength()*1000; callCdr.setCallTime(newDate(time)); } //todo保存到数据库 Useruser=userService.selectOne(newEntityWrapper ().eq("extension",callCdr.getExtensionNum()+"")); callCdr.setUserName(user.getUserName()); callCdr.setCorpCode(user.getCorpCode()); callCdr.setCreater(user.getId()); callCdr.setId(UUIDUtil.genUUID()); callCdr.setCreateTime(newDate()); PhoneModelphoneModel=PhoneUtils.getPhoneModel(callCdr.getCustomerPhone()); if(phoneModel!=null){ callCdr.setCustomerCity(phoneModel.getCityName()); callCdr.setCustomerProvince(phoneModel.getProvinceName()); } callCdr.setCallId(System.currentTimeMillis()+""+callCdr.getCallId()); bucket.set(callCdr); CallRecordcallRecord=callCdr; booleanresult=callRecordService.insert(callRecord); if(result){ bucket.delete(); } } privatevoidsaveVistorCdr(){ CallCdrcallCdr=null; RBucket 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()); PhoneModelphoneModel=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())); Useruser=userService.selectOne(newEntityWrapper ().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())){ //用户在坐席未接来电时未接来电无录音挂机 intringLength=(int)((newDate().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())); } }elseif(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); intringLength=(int)((newDate().getTime()-callCdr.getCallTime().getTime())/1000); callCdr.setRingLength(ringLength); } callCdr.setCreateTime(newDate()); callCdr.setHangupTime(newDate()); 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())){ }elseif(Objects.equals(CdrType.UNUSUAL,callCdr.getLastEvent())){ }else{ CallRecordcallRecord=callCdr; booleanresult=callRecordService.insert(callRecord); if(result){ bucket.delete(); } } } }
2、获取bean的工具类
packagecom.ps.uzkefu.apps.ctilink.init; importorg.springframework.beans.BeansException; importorg.springframework.context.ApplicationContext; importorg.springframework.context.ApplicationContextAware; importorg.springframework.stereotype.Component; /** *Author:ZhuShangJin *Date:2018/7/3 */ @Component publicclassApplicationContextProviderimplementsApplicationContextAware{ /** *上下文对象实例 */ privatestaticApplicationContextapplicationContext; @Override publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{ this.applicationContext=applicationContext; } /** *获取applicationContext * *@return */ publicstaticApplicationContextgetApplicationContext(){ returnapplicationContext; } /** *通过name获取Bean. * *@paramname *@return */ publicstaticObjectgetBean(Stringname){ returngetApplicationContext().getBean(name); } /** *通过class获取Bean. * *@paramclazz *@param*@return */ publicstatic TgetBean(Class clazz){ returngetApplicationContext().getBean(clazz); } /** *通过name,以及Clazz返回指定的Bean * *@paramname *@paramclazz *@param *@return */ publicstatic TgetBean(Stringname,Class clazz){ returngetApplicationContext().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 *@authorChenYongJia *@Date2019年6月26日晚上21:20 *@Emailchen87647213@163.com */ @Component publicclassXXUtils{ @Autowired privateSpecialLogSevicesevice; privatestaticSpecialLogSevicespecialLogSevice; @PostConstruct publicvoidinit(){ specialLogSevice=sevice; } //下面的内容就省略了,需要调用specialLogSevice打点就行了 }
在上述代码中@PostConstruct是JavaEE5规范之后,Servlet新增的两个影响servlet声明周期的注解之一,另外一个是@PreConstruct。这两个都可以用来修饰一个非静态的返回值为void的方法,并且该方法不能抛出异常。
被@PostConstruct注解修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet中的init方法。被该注解修饰的方法会在构造器执行之后,init方法执行之前执行。Spring中允许开发者在受理的Bean中去使用它,当IOC容器被实例化管理当前bean时,被该注解修饰的方法会执行,完成一些初始化的工作。
被PreConstruct注解修饰的方法会在服务器卸载Servlet的时候运行,类似于Servlet中的destroy方法。被该注解修饰的方法会在destroy方法执行之后,Servlet彻底卸载之前执行。
到这里:关于Spring/SpringBoot在静态工具类中注入Service的解决方案!分享完毕了,快去试试吧!希望大家多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。