这里写自定义目录标题

摘要

项目中用到了多线程,但是线程异步操作时无法调用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

如有哪里理解的不好的或不足之处,欢迎您的指出
每天进步一点点!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐