解決SpringBoot2多線程無法注入的問題
1、情況描述
使用springboot2多線程,線程類無法實現(xiàn)自動注入需要的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 保存到數(shù)據(jù)庫
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在靜態(tài)工具類中注入Service的解決方案
前言今天博主將為大家分享:關于Spring/SpringBoot在靜態(tài)工具類中注入Service的解決方案!不喜勿噴,如有異議歡迎討論!
最近遇到了需要在工具類中注入Service,由于工具類中方法一般都是靜態(tài)的,所以要求該屬性也要是靜態(tài)的(Service)。但是由于Spring/SpringBoot正常情況下不能支持注入靜態(tài)屬性(會報空指針異常)。主要原因在于:Spring的依賴注入實際上是依賴于Set方法進行注入值的,Spring是基于對象層面的依賴注入,而靜態(tài)屬性/靜態(tài)變量實際上是屬于類的。
解決方案:
給當前的工具類加上@Component,使其成為一個bean對象
聲明一個靜態(tài)的屬性(加上注解@Autowired),一個非靜態(tài)的屬性。
聲明一個返回值為void并且不能拋出異常的方法,在其中將非靜態(tài)屬性賦值給靜態(tài)屬性。該方法上加上注解@PostConstruct
這樣就將service的值注入了進來。示例代碼如下:
/**
*
*@Description: 關于Spring/SpringBoot在靜態(tài)工具類中注入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;
}
//下面的內(nèi)容就省略了,需要調(diào)用specialLogSevice打點就行了
}
在上述代碼中@PostConstruct是Java EE5規(guī)范之后,Servlet新增的兩個影響servlet聲明周期的注解之一,另外一個是@PreConstruct。這兩個都可以用來修飾一個非靜態(tài)的返回值為void的方法,并且該方法不能拋出異常。
被@PostConstruct注解修飾的方法會在服務器加載Servlet的時候運行,并且只會被服務器調(diào)用一次,類似于Servlet中的init方法。被該注解修飾的方法會在構造器執(zhí)行之后,init方法執(zhí)行之前執(zhí)行。Spring中允許開發(fā)者在受理的Bean中去使用它,當IOC容器被實例化管理當前bean時,被該注解修飾的方法會執(zhí)行,完成一些初始化的工作。
被PreConstruct注解修飾的方法會在服務器卸載Servlet的時候運行,類似于Servlet中的destroy方法。被該注解修飾的方法會在destroy方法執(zhí)行之后,Servlet徹底卸載之前執(zhí)行。
到這里:關于Spring/SpringBoot在靜態(tài)工具類中注入Service的解決方案!分享完畢了,快去試試吧!希望大家多多支持腳本之家!
相關文章
使用httpclient無需證書調(diào)用https的示例(java調(diào)用https)
這篇文章主要介紹了使用httpclient無需證書調(diào)用https的示例(java調(diào)用https),需要的朋友可以參考下2014-04-04
jdk8?FunctionalInterface注解源碼解讀
這篇文章主要介紹了jdk8?FunctionalInterface注解源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11
解析Java?中for循環(huán)和foreach循環(huán)哪個更快
這篇文章主要介紹了Java中for循環(huán)和foreach循環(huán)哪個更快示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09

