背景
- 最近在做一个大数据的项目,需要在项目中加点定时任务。按照之前的经验已经用过很多次的Quartz无疑是最佳的选择。
- 由于之前的项目用Quartz并没有持久化,所有Job中的bean是直接通过jobDataMap进行传递。但本次需要持久化,bean是无法通过Quartz持久化到DB,会报错。
- 而在 Quartz 的 Job 中 @Autowired 一个 Spring Bean 的时候会报空指针异常。
原因
- 出现这个问题是因为定时任务的 Job 对象实例化的过程是通过 Quartz 内部自己完成的,但是我们通过 Spring 进行注入的 Bean 却是由 Spring 容器管理的,Quartz 内部无法感知到 Spring 容器管理的 Bean,所以没有办法在创建 Job 的时候就给装配进去。
- 经过对源码的分析,发现比较复杂,需要自己定义一个JobFactory交给spring管理,同时还得将自定义的 JobFactory 设置到 Schedule中,相对来说比较复杂。
- 上述方案有点复杂(主要是代码比较多)。既然我们依赖的bean是已经由spring管理的,那么我们取出来用不就好?也即是通过getBean方法直接取值。这种方法可以实现目的,同时分析了下好像也没有啥特别大的弊端 (若有求指点)
代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;
/**
* Created by linzikang
*/
@Component
public class SpringUtil implements ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringUtil.class);
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringUtil.context = context;
}
/**
* 获取 Spring Bean
* @param clazz 类
* @param <T> 泛型
* @return 对象
*/
public static <T> T getBean(Class<T> clazz) {
if (clazz == null) {
return null;
}
return context.getBean(clazz);
}
/**
* 获取 Spring Bean
* @param bean 名称
* @param <T> 泛型
* @return 对象
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String bean) {
if (bean == null) {
return null;
}
return (T) context.getBean(bean);
}
/**
* 获取 Spring Bean
* @param beanName 名称
* @param clazz 类
* @param <T> 泛型
* @return 对象
*/
public static <T> T getBean(String beanName, Class<T> clazz) {
if (null == beanName || "".equals(beanName.trim())) {
return null;
}
if (clazz == null) {
return null;
}
return (T) context.getBean(beanName, clazz);
}
/**
* 获取上下文
* @return 上下文
*/
public static ApplicationContext getContext() {
if (context == null) {
throw new RuntimeException("There has no Spring ApplicationContext!");
}
return context;
}
/**
* 发布事件
* @param event 事件
*/
public static void publishEvent(ApplicationEvent event) {
if (context == null) {
return;
}
try {
context.publishEvent(event);
} catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
}
}
- bean获取:直接调用SpringUtil.getBean(xxx.class)即可,只有你的bean已经被spring托管过的,那么在任何地方都可以调用到。
网友评论