做项目的时候遇见一个问题,其实以前也遇到过类似的,虽然最后用new ClassPathXmlApplicationContext的方式解决了,但是也是治标不治本。
今天再次遇见,总结一下原因和目前觉得比较好的解决方法吧!
情形:
首先我通过Spring中Quartz的Factory工厂来创建Job,这个job其实是一个调度管理器,动态读取数据库的信息,然后再创建和管理更多的job。
<bean id="SpringQtzJobMethod"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="SpringQtzJob" />
</property>
<property name="targetMethod">
<!-- 需要执行的方法名称 -->
<value>init</value>
</property>
</bean>
当我再用java创建job的以后,发现我实现job接口的类中所有的bean都没办法注入了。原因:
我通过反射的方式创建job类(代码中实现),而不是用Spring来创建(不是Spring容器中的实例),所以获取不到bean。
其实还有一种配置方式,也是反射的方式创建:
<bean name="initJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.xxx.services.InitJob" />
</bean>
解决方案:
job的实现每次都会创建一个任务实例,如果在job中去做new ClassPathXmlApplicationContext("classpath*:xxx");的话可以解决上面的情况,但是job每次都会创建一个实例,这样在高并发或者长时间使用下,很容易就会内存溢出;
因此,比较好的解决办法是在spring配置文件中加入ApplicationContextAware 的实现类SpringContextUtil ,让spring在初始化的时候做一次需要使用的service或dao的bean初始化,这样在job中就可以通过这个util去拿到已经初始化的实例,而不用每次都创建一次context。
package com.framework.util;
import java.util.Locale;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 系统bean帮助类
*/
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
@SuppressWarnings("static-access" )
public void setApplicationContext(ApplicationContext contex)
throws BeansException {
// TODO Auto-generated method stub
this.context = contex;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
public static String getMessage(String key){
return context.getMessage(key, null, Locale.getDefault());
}
}
在spring的配置中加上这个util
<bean id="SpringContextUtil" class="com.framework.util.SpringContextUtil"></bean>
调用的时候这样做
TfUserChargeService tfUserChargeService = (TfUserChargeService)SpringContextUtil.getBean("tfUserChargeService");
List<TfProductMonthCharge> chargeList= tfUserChargeService.countProductMonthCharge(lastMonth);
......
之前也写过一篇spring中bean的获取方式总结,连接http://blog.youkuaiyun.com/a714832876/article/details/47661003