现在Spring配置内容越来越多,初始化需要的时间也越来越多。这时候quartz启动,Job在另外一个线程去试图获取Bean,有一定死锁的机率。
这个是找到的一个官方认可的bug,但尚未修复
https://jira.springsource.org/browse/SPR-9199
一个改造方法是是的job采用@autowired 尽可能通过注入bean,我觉得这是最好的方式,但有可能不灵活
另外一个临时解决方法是将job启动尽可能延迟多一点,以等待spring主线程初完毕
还有一个方法是将quartz启动延迟到spring初始化完毕后,即监听spring 的 ContextRefreshedEvent事件,然后启动schedule。此实现方法稍微有点复杂,参考附件,说明如下:
public class MySchedulerFactoryBean extends SchedulerFactoryBean implements ApplicationListener, Ordered
{
public MySchedulerFactoryBean()
{
super();
}
// public void start() throws SchedulingException
// {
// super.start();
// System.out.println("start ");
// }
@Override
public void onApplicationEvent(ApplicationEvent event)
{
if (event instanceof ContextRefreshedEvent)
{
System.out.println(" spring init finsihed");
super.start();
}
}
@Override
public int getOrder()
{
return 100;
}
}
所有的配置文件都做如下相应改动
<bean class="com.netease.XXXX.MySchedulerFactoryBean">
<property name="autoStartup" value="false" />
<property name="triggers">
<list>
<ref bean="jobTestDetailTrigger" />
</list>
</property>
</bean>
即将spring提供的SchedulerFactoryBean 改成我们自己的
另外有一处改动就是,但可以保证spring按照我们定义的顺序调用Linstener从而初始化系统各种数据
按照所有Lisener的优先级(通过实现ordered方法)来顺序调用这些Liseneer
<bean id="applicationEventMulticaster" class="com.netease.lottery.util.MyApplicationEventMulticaster"/>
MyApplicationEventMulticaster实现可以参考spring提供的SimpleApplicationEventMulticaster
代码如下:
package com.netease.lottery.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.core.Ordered;
public class MyApplicationEventMulticaster implements ApplicationEventMulticaster
{
Set<ApplicationListener> list = new HashSet<ApplicationListener>();
@Override
public void addApplicationListener(ApplicationListener listener)
{
list.add(listener);
}
@Override
public void removeApplicationListener(ApplicationListener listener)
{
list.remove(listener);
}
@Override
public void removeAllListeners()
{
list = new HashSet<ApplicationListener>();
}
@Override
public void multicastEvent(ApplicationEvent event)
{
List target = new ArrayList(list);
Collections.sort(target, new Comparator() {
@Override
public int compare(Object o1, Object o2)
{
ApplicationListener l1 = (ApplicationListener) o1;
ApplicationListener l2 = (ApplicationListener) o2;
int p1 = Ordered.LOWEST_PRECEDENCE;
int p2 = Ordered.LOWEST_PRECEDENCE;
if (l1 instanceof Ordered)
{
p1 = ((Ordered) l1).getOrder();
}
if (l2 instanceof Ordered)
{
p2 = ((Ordered) l2).getOrder();
}
return p1 - p2;
}
});
for (int i = 0; i < target.size(); i++)
{
ApplicationListener l = (ApplicationListener) target.get(i);
l.onApplicationEvent(event);
}
}
}
总共有这三种方法可以解决,个人觉得第三种是最周全和灵活的方式
|