解决SpringBoot2多线程无法注入的问题

时间:2022-08-23 18:55:54

1、情况描述

使用springboot2多线程,线程类无法实现自动注入需要的bean,解决思路,通过工具类获取需要的bean

如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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的工具类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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的值注入了进来。示例代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
*
*@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的解决方案!分享完毕了,快去试试吧!希望大家多多支持服务器之家!

原文链接:https://blog.csdn.net/zsj777/article/details/80965081