摘要
項目中用到了多線程,但是線程異步操作時無法調用Service層和Dao層的函數,進行數據庫的讀取,然後就想辦法如何往異步線程中注入Service和Dao層的bean。
剛開始的思路
之前瞭解到,根據Spring的特性,Spring容器中的Service層和Dao層的Bean都是單例模式,所以我想在我的NotifyRunable類中設置一個靜態字段,把 service層的bean賦值給這個靜態字段是不是就可以調用了,進行業務查詢和處理。
但是什麼時候進行賦值呢?一開始的思路是,Spring是在容器初始化時把每個字段進行注入操作的,所以我就想初始化完吧值賦值給NotifyRunable類的靜態字段就可以了,這時候我想到了@PostConstruct這個註解,這個註解可以在某個bean初始化完成後執行註解的方法,於是就有了以下代碼,經測試可用。
//service類
@Service
public class DeepServiceImpl implements DeepService {
@Autowired
private PersonDao personDao;
/**
* 初始化時,初始化notify對象
*/
@PostConstruct
public void initDeepface() {
/*這裏是關鍵步驟,通過 ==@PostConstruct== 註解,在service初始化時注入到線程類裏面*/
NotifyRunable.setPersonDao(personDao);
}
}
//線程類Runnable
public class NotifyRunable implements Runnable {
private static PersonDao personDao;
@Override
public void run() {
//讀取數據庫的小明
personDao.get("xiaoming");
}
public static PersonDao getPersonDao() {
return personDao;
}
public static void setPersonDao(PersonDao personDao) {
NotifyRunable.personDao = personDao;
}
}
這就解決了問題,但是後來感覺這樣代碼的解耦性比較差,NotifyRunable的初始化依賴其它類,自其它類中進行,而且使用靜態字段也感覺不太好,於是想了其他方法。
另一種方法
能不能在NotifyRunable自己new的時候在構造函數中賦值賦值呢?答案是:可以!
我們只需要在構造函數中獲取Spring 容器的上下文就可以獲取到Service和Dao層的Bean實體了。
我們用以下方式獲取,這樣就可以
public class WechatNotifyRunable implements Runnable {
private final Logger logger = Logger.getLogger(WechatNotifyRunable.class);
private static List<JSONObject> notifyList = new ArrayList<JSONObject>();
private UserInfoDao userInfoDao;
private CheckInOutDao checkInOutDao;
private UserinfoMachinesDao userinfoMachinesDao;
private FaceApplyDao faceApplyDao;
private PersonDao personDao;
private LocalCacheRedisDao localCacheRedisDao;
private MachineDao machineDao;
private static ThreadPoolTaskExecutor jobtaskExecutor;
// 保存上一個personid
public static HashMap<String, Long> lastPersonMap = new HashMap<String, Long>();
// 保存上一個Transactionid
public static HashMap<String, Long> lastTransactionMap = new HashMap<String, Long>();
/**
* 構造函數,初始化dao層對象
*/
public WechatNotifyRunable() {
//獲取子容器sevlet, 不能獲取父容器root,父容器中不存在service和dao實體bean
ServletRequestAttributes sevletRequestAttributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sevletRequestAttributes.getRequest();
WebApplicationContext servletContext = (WebApplicationContext)
request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
//從容器中獲取Dao層Bean
userInfoDao = servletContext.getBean("userInfoDaoImpl",UserInfoDao.class);
localCacheRedisDao = servletContext.getBean(LocalCacheRedisDao.class);
}
@Override
public void run() {
}
}
這裏補充一下,在獲取Spring容器時遇到了一個問題,容器中不存在這個Bean實體,這個是因爲剛開始獲取的是Spring的Root容器,而Service和Dao的Bean在Spring MVC的Sevlet容器中,這個到下一集講。
pringMVC中的RootWebApplicationContext與ServletWebApplicationContext區別
提示錯誤如下
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [cn.xdf.wlyy.attendance.dao.PersonDao] is defined
如有哪裏理解的不好的或不足之處,歡迎您的指出
每天進步一點點!