最近一个项目使用listener 触发一个定时器轮询入库,可悲的发现执行类注入的javabean为null;google下来的方法不起作用,就来这里求大神帮忙了。
Timer timer = new Timer(true);
GrddSaveTask task = new GrddSaveTask();//这里由于listener早于servlet初始化,所以task注入参数为空。
timer.schedule(task, 1, 20);
如何在真正使用的时候,因为使用的时候spring已经启动了,给需要注入的Mng初始化。
或者如何子在一个非spring控制的类中获得当前环境中的spring Context。

解决方案 »

  1.   

    /**
     * 服务器启动关闭的监听器
     * @version 1.0
     */
    public class GlobalListener implements ServletContextListener {

    private static final Logger log = LoggerFactory.getLogger(GlobalListener.class);
    private Timer timer = new Timer(); /**
     * 关闭服务器
     */
    public void contextDestroyed(ServletContextEvent event) {
    log.info("关闭服务器");
    timer.cancel();
    } /**
     * 启动服务器
     */
    public void contextInitialized(ServletContextEvent event) {
    log.info("启动服务器");
    FrameConfig.waterImgPath = "/common_res/images/water.jpg";
    FrameConfig.maxCacheSize = 10000;
    FrameConfig.encoding = "UTF-8";
    timer.schedule(new TaskTimer(), getMillisecond(), Task.daySeconds * 1000l);// 每天执行一次
    }

    // 从现在到明天最早时间相差的毫秒数
    private Long getMillisecond() {
    DateUtil util = DateUtil.getBean();
    String beginTime = util.getDetachDate(util.getNowDate(0) + " 00:00:00", 2, Task.daySeconds.intValue());
    return util.getDateDiff(util.getNowDate(1), beginTime) * 1000l;
    }}
    /**
     * 每天最早时间刷新客服回访任务的定时器
     * @version 1.0
     */
    public class TaskTimer extends TimerTask {

    private static final Logger log = LoggerFactory.getLogger(TaskTimer.class); @Override
    public void run() {
    TaskMng mng = (TaskMng) BeanContainer.getBean(TaskMng.class);
    Integer num = mng.renovate();
    log.info("今天最早时间产生了" + num + "个客服回访任务");
    CrmHistory.CRM_HISTORY_MAP = new HashMap<String, List<CrmHistory>>();
    }}web.xml
    <listener>
    <listener-class>com.xxx.GlobalListener</listener-class>
    </listener>
      

  2.   

    如果spring的调用方和web容易有关联,因为spring的上下文一般是随web容器启动的,所以获取spring的bean一般可以通过web容器的上下文直接拿到,代码如下: WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
    但是这种方式过渡依赖web容器,如果是单独类想用spring中的bean此方案不可用;
    如果调用方也被spring配置管理,那可以用注解,get/set,构造器来获取spring中的其他bean
    如果调用方既没有被spring管理,也没有和容器上下文有任何关系,想获取spring中的bean,只能借助BeanFactory工厂了,由工厂来为你创造,好多人就会想到用ClassPathXmlApplicationContext类似方式重新加载一遍spring配置构造一个ApplicationContext上下文或者一个工厂,岂不知这样做就会产生两个spring环境的上下文,另一个就是web端启动了一个spring环境上下文,我们如何只让spring的环境只启动一次呢?答案很简单,代码如下:
    <bean id="serviceLocator" class="org.androidpn.server.service.ServiceLocator" scope="singleton" /> 
    在spring的配置文件中配置一个serviceLocator,让web容器启动spring的时候将spring的上下文(也就是BeanFactory)传到我们定义的serviceLocator类中,代码如下:public class ServiceLocator implements BeanFactoryAware {
        private static BeanFactory beanFactory = null;    private static ServiceLocator servlocator = null;    public void setBeanFactory(BeanFactory factory) throws BeansException {
    this.beanFactory = factory;
        }    public BeanFactory getBeanFactory() {
    return beanFactory;
        }    public static ServiceLocator getInstance() {
    if (servlocator == null)
        servlocator = (ServiceLocator) beanFactory.getBean("serviceLocator");
    return servlocator;
        }
        /**
         * 根据提供的bean名称得到相应的服务类
         * 
         * @param servName
         *            bean名称
         */
        public static Object getService(String servName) {
    return beanFactory.getBean(servName);
        }
    }
    这样在你的工程中任何地方想获取到spring上下文中的bean实例都可以通过ServiceLocator类来获得,堪称两全其美,内圣外王!!