Java異步線程中調用Spring容器中Service和Dao的 Bean,以進行數據庫和業務的操作

這裏寫自定義目錄標題

摘要

項目中用到了多線程,但是線程異步操作時無法調用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

如有哪裏理解的不好的或不足之處,歡迎您的指出
每天進步一點點!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章