`
Donald_Draper
  • 浏览: 951846 次
社区版块
存档分类
最新评论

JobDetailFactoryBean与MethodInvokingJobDetailFactoryBean源码分析

 
阅读更多
Spring与Quartz集成详解:http://donald-draper.iteye.com/blog/2323591
Spring与Quarzt整合时,job的定义有两种方式,分别为JobDetailFactoryBean与MethodInvokingJobDetailFactoryBean,这两种方法有什么不同呢,我们通过源码来看一下:
第一种:
public class JobDetailFactoryBean
    implements FactoryBean, BeanNameAware, ApplicationContextAware, InitializingBean
{
  public JobDetailFactoryBean()
    {
        jobDataMap = new JobDataMap();
        durability = false;
        requestsRecovery = false;
    }
     public void setName(String name)
    {
        this.name = name;
    }

    public void setGroup(String group)
    {
        this.group = group;
    }

     public void setDescription(String description)
    {
        this.description = description;
    }
     //设置beanName
    public void setBeanName(String beanName)
    {
        this.beanName = beanName;
    }
    //设置applicationContext
    public void setApplicationContext(ApplicationContext applicationContext)
    {
        this.applicationContext = applicationContext;
    }
    //设置applicationContextJobDataKey
    public void setApplicationContextJobDataKey(String applicationContextJobDataKey)
    {
        this.applicationContextJobDataKey = applicationContextJobDataKey;
    }
    public void afterPropertiesSet()
    {
        //设置默认的job,name和group
        if(name == null)
            name = beanName;
        if(group == null)
            group = "DEFAULT";
        if(applicationContextJobDataKey != null)
        {
            if(applicationContext == null)
                throw new IllegalStateException("JobDetailBean needs to be set up in an ApplicationContext to be able to handle an 'applicationContextJobDataKey'");
            //配置jobDataMap
	    getJobDataMap().put(applicationContextJobDataKey, applicationContext);
        }
        Class jobDetailClass;
        try
        {
            jobDetailClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", getClass().getClassLoader());
        }
        catch(ClassNotFoundException ex)
        {
            jobDetailClass = org/quartz/JobDetail;
        }
        BeanWrapper bw = new BeanWrapperImpl(jobDetailClass);
	
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.add("name", name);
        pvs.add("group", group);
        pvs.add("jobClass", jobClass);
        pvs.add("jobDataMap", jobDataMap);
        pvs.add("durability", Boolean.valueOf(durability));
        pvs.add("requestsRecovery", Boolean.valueOf(requestsRecovery));
        pvs.add("description", description);
	//设置属性
        bw.setPropertyValues(pvs);
	//或JobDetail实例
        jobDetail = (JobDetail)bw.getWrappedInstance();
    }
     //设置属性值
     public void setPropertyValue(String propertyName, Object value)
        throws BeansException
    {
        BeanWrapperImpl nestedBw;
        try
        {
            nestedBw = getBeanWrapperForPropertyPath(propertyName);
        }
        PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName));
        nestedBw.setPropertyValue(tokens, new PropertyValue(propertyName, value));
    }
    //设置job类
    public void setJobClass(Class jobClass)
    {
        this.jobClass = jobClass;
    }
    //返回的是jobDetail
     public JobDetail getObject()
    {
        return jobDetail;
    }

    public Class getObjectType()
    {
        return org/quartz/JobDetail;
    }

    public boolean isSingleton()
    {
        return true;
    }

    public volatile Object getObject()
        throws Exception
    {
        return getObject();
    }
    private String name;
    private String group;
    private Class jobClass;
    private JobDataMap jobDataMap;
    private boolean durability;//任务完成之后是否依然保留到数据库,默认false
    private boolean requestsRecovery;
    private String description;
    private String beanName;
    private ApplicationContext applicationContext;
    private String applicationContextJobDataKey;
    private JobDetail jobDetail;
}

//bean包装实现类
public class BeanWrapperImpl extends AbstractPropertyAccessor
    implements BeanWrapper
{

     public BeanWrapperImpl(Class clazz)
    {
        nestedPath = "";
        autoGrowNestedPaths = false;
        autoGrowCollectionLimit = 2147483647;
        registerDefaultEditors();
	//设置bean包装实现类实例
        setWrappedInstance(BeanUtils.instantiateClass(clazz));
    }
     public void setWrappedInstance(Object object)
    {
        setWrappedInstance(object, "", null);
    }
    public void setWrappedInstance(Object object, String nestedPath, Object rootObject)
    {
        Assert.notNull(object, "Bean object must not be null");
        this.object = object;
        this.nestedPath = nestedPath == null ? "" : nestedPath;
        this.rootObject = "".equals(this.nestedPath) ? object : rootObject;
        nestedBeanWrappers = null;
        typeConverterDelegate = new TypeConverterDelegate(this, object);
        setIntrospectionClass(object.getClass());
    }
     protected void setIntrospectionClass(Class clazz)
    {
        if(cachedIntrospectionResults != null && !clazz.equals(cachedIntrospectionResults.getBeanClass()))
            cachedIntrospectionResults = null;
    }
    //返回包装类实例
      public final Object getWrappedInstance()
    {
        return object;
    }
    private static final Log logger = LogFactory.getLog(org/springframework/beans/BeanWrapperImpl);
    private Object object;
    private String nestedPath;
    private Object rootObject;
    private AccessControlContext acc;
    private CachedIntrospectionResults cachedIntrospectionResults;
    private Map nestedBeanWrappers;
    private boolean autoGrowNestedPaths;
    private int autoGrowCollectionLimit;


}

//AbstractPropertyAccessor
public abstract class AbstractPropertyAccessor extends TypeConverterSupport
    implements ConfigurablePropertyAccessor
{
    //设置bean所有属性
    public void setPropertyValues(PropertyValues pvs)
        throws BeansException
    {
        setPropertyValues(pvs, false, false);
    }
    //设置bean所有属性
    public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
        throws BeansException
    {
        List propertyAccessExceptions = null;
        List propertyValues = (pvs instanceof MutablePropertyValues) ? ((MutablePropertyValues)pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues());
        Iterator iterator = propertyValues.iterator();
        do
        {
            if(!iterator.hasNext())
                break;
            PropertyValue pv = (PropertyValue)iterator.next();
            try
            {
                setPropertyValue(pv);
            }
            
        } while(true)
    }
    //设置bean单个属性
    public void setPropertyValue(PropertyValue pv)
        throws BeansException
    {
        setPropertyValue(pv.getName(), pv.getValue());
    }
}

第二种:
public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker
    implements FactoryBean, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean
{
    public static class StatefulMethodInvokingJob extends MethodInvokingJob
        implements StatefulJob
    {}

    public static class MethodInvokingJob extends QuartzJobBean
    {
     public void setMethodInvoker(MethodInvoker methodInvoker)
        {
            this.methodInvoker = methodInvoker;
        }
        protected void executeInternal(JobExecutionContext context)
            throws JobExecutionException
        {
            try
            {
                ReflectionUtils.invokeMethod(MethodInvokingJobDetailFactoryBean.setResultMethod, context, new Object[] {
                    methodInvoker.invoke()
                });
            }
        }
    }
	public MethodInvokingJobDetailFactoryBean()
    {
        group = "DEFAULT";
        concurrent = true;
        beanClassLoader = ClassUtils.getDefaultClassLoader();
    }
     public void afterPropertiesSet()
        throws ClassNotFoundException, NoSuchMethodException
    {
        //初始化MethodInvoker
        prepare();
        String name = this.name == null ? beanName : this.name;
        Class jobClass = concurrent ? org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean$MethodInvokingJob : org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean$StatefulMethodInvokingJob;
        if(jobDetailImplClass != null)
        {
            jobDetail = (JobDetail)BeanUtils.instantiate(jobDetailImplClass);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(jobDetail);
            bw.setPropertyValue("name", name);
            bw.setPropertyValue("group", group);
            bw.setPropertyValue("jobClass", jobClass);
            bw.setPropertyValue("durability", Boolean.valueOf(true));
	    //设置jobDetails的jobDataMap
            ((JobDataMap)bw.getPropertyValue("jobDataMap")).put("methodInvoker", this);
        } else
        {
            jobDetail = new JobDetail(name, group, jobClass);
            jobDetail.setVolatility(true);
            jobDetail.setDurability(true);
            jobDetail.getJobDataMap().put("methodInvoker", this);
        }
        if(jobListenerNames != null)
        {
            String as[] = jobListenerNames;
            int i = as.length;
            for(int j = 0; j < i; j++)
            {
                String jobListenerName = as[j];
                if(jobDetailImplClass != null)
                    throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - manually register a Matcher against the Quartz ListenerManager instead");
                //添加job监听器
		jobDetail.addJobListener(jobListenerName);
            }

        }
        postProcessJobDetail(jobDetail);
    }

    protected void postProcessJobDetail(JobDetail jobdetail)
    {
    }
    //获取目标类型
    public Class getTargetClass()
    {
        Class targetClass = super.getTargetClass();
        if(targetClass == null && targetBeanName != null)
        {
            Assert.state(beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
            targetClass = beanFactory.getType(targetBeanName);
        }
        return targetClass;
    }
   //获取目标实例
    public Object getTargetObject()
    {
        Object targetObject = super.getTargetObject();
        if(targetObject == null && targetBeanName != null)
        {
            Assert.state(beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
            targetObject = beanFactory.getBean(targetBeanName);
        }
        return targetObject;
    }
   //返回jobDetail
    public JobDetail getObject()
    {
        return jobDetail;
    }

    public Class getObjectType()
    {
        return jobDetail == null ? org/quartz/JobDetail : jobDetail.getClass();
    }

    public boolean isSingleton()
    {
        return true;
    }
    public volatile Object getObject()
        throws Exception
    {
        return getObject();
    }
    private static Class jobDetailImplClass;
    private static Method setResultMethod;
    private String name;
    private String group;
    private boolean concurrent;
    private String targetBeanName;
    private String jobListenerNames[];
    private String beanName;
    private ClassLoader beanClassLoader;
    private BeanFactory beanFactory;
    private JobDetail jobDetail;

    static 
    {
        try
        {
            jobDetailImplClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.getClassLoader());
        }
        try
        {
            Class jobExecutionContextClass = ClassUtils.forName("org.quartz.JobExecutionContext", org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.getClassLoader());
            setResultMethod = jobExecutionContextClass.getMethod("setResult", new Class[] {
                java/lang/Object
            });
        }      
    }
 }

//方法包装类
public class MethodInvoker
{
     public void prepare()
        throws ClassNotFoundException, NoSuchMethodException
    {
        if(staticMethod != null)
        {
            int lastDotIndex = staticMethod.lastIndexOf('.');
            if(lastDotIndex == -1 || lastDotIndex == staticMethod.length())
                throw new IllegalArgumentException("staticMethod must be a fully qualified class plus method name: e.g. 'example.MyExampleClass.myExampleMethod'");
            String className = staticMethod.substring(0, lastDotIndex);
            String methodName = staticMethod.substring(lastDotIndex + 1);
            this.targetClass = resolveClassName(className);
            this.targetMethod = methodName;
        }
        Class targetClass = getTargetClass();
        String targetMethod = getTargetMethod();
        if(targetClass == null)
            throw new IllegalArgumentException("Either 'targetClass' or 'targetObject' is required");
        if(targetMethod == null)
            throw new IllegalArgumentException("Property 'targetMethod' is required");
        Object arguments[] = getArguments();
        Class argTypes[] = new Class[arguments.length];
        for(int i = 0; i < arguments.length; i++)
            argTypes[i] = arguments[i] == null ? java/lang/Object : arguments[i].getClass();

        try
        {
	   //获取targetClass的targetMethod方法,参数为argTypes
            methodObject = targetClass.getMethod(targetMethod, argTypes);
        }
        catch(NoSuchMethodException ex)
        {
            methodObject = findMatchingMethod();
            if(methodObject == null)
                throw ex;
        }
    }

    //反射调用方法
    public Object invoke()
        throws InvocationTargetException, IllegalAccessException
    {
        Object targetObject = getTargetObject();
        Method preparedMethod = getPreparedMethod();
        if(targetObject == null && !Modifier.isStatic(preparedMethod.getModifiers()))
        {
            throw new IllegalArgumentException("Target method must not be non-static without a target");
        } else
        {
            ReflectionUtils.makeAccessible(preparedMethod);
	    //执行目标targetObject的目标方法targetMethod,参数为arguments[]
            return preparedMethod.invoke(targetObject, getArguments());
        }
    }
    //jobDetails类的方法
    public Method getPreparedMethod()
        throws IllegalStateException
    {
        if(methodObject == null)
            throw new IllegalStateException("prepare() must be called prior to invoke() on MethodInvoker");
        else
            return methodObject;
    }
     public Object getTargetObject()
    {
        return targetObject;
    }
    public String getTargetMethod()
    {
        return targetMethod;
    }
    private Class targetClass;//目标类
    private Object targetObject;//目标实体
    private String targetMethod;//目标方法
    private String staticMethod;
    private Object arguments[];
    private Method methodObject;
}

最后再来看一下触发器任务工厂类
//触发器任务工厂类
public class CronTriggerFactoryBean
    implements FactoryBean, BeanNameAware, InitializingBean
{

    public CronTriggerFactoryBean()
    {
        jobDataMap = new JobDataMap();
        startDelay = 0L;
    }
    
    public void afterPropertiesSet()
    {
        if(name == null)
            name = beanName;
        if(group == null)
            group = "DEFAULT";
        if(jobDetail != null)
            jobDataMap.put("jobDetail", jobDetail);
        if(startDelay > 0L || startTime == null)
            startTime = new Date(System.currentTimeMillis() + startDelay);
        if(timeZone == null)
            timeZone = TimeZone.getDefault();
        Class cronTriggerClass;
        Method jobKeyMethod;
        try
        {
            cronTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.CronTriggerImpl", getClass().getClassLoader());
            jobKeyMethod = org/quartz/JobDetail.getMethod("getKey", new Class[0]);
        }
	//新建cronTriggerClass的包装类
        BeanWrapper bw = new BeanWrapperImpl(cronTriggerClass);
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.add("name", name);
        pvs.add("group", group);
        if(jobKeyMethod != null)
        {
            pvs.add("jobKey", ReflectionUtils.invokeMethod(jobKeyMethod, jobDetail));
        } else
        {
            pvs.add("jobName", jobDetail.getName());
            pvs.add("jobGroup", jobDetail.getGroup());
        }
        pvs.add("jobDataMap", jobDataMap);
        pvs.add("startTime", startTime);
        pvs.add("cronExpression", cronExpression);
        pvs.add("timeZone", timeZone);
        pvs.add("calendarName", calendarName);
        pvs.add("priority", Integer.valueOf(priority));
        pvs.add("misfireInstruction", Integer.valueOf(misfireInstruction));
        pvs.add("description", description);
	//设置CronTrigger属性
        bw.setPropertyValues(pvs);
	//获取CronTrigger实例
        cronTrigger = (CronTrigger)bw.getWrappedInstance();
    }
    //返回Cron触发器
     public CronTrigger getObject()
    {
        return cronTrigger;
    }
    public Class getObjectType()
    {
        return org/quartz/CronTrigger;
    }

    public boolean isSingleton()
    {
        return true;
    }

    public volatile Object getObject()
        throws Exception
    {
        return getObject();
    }
    private static final Constants constants = new Constants(org/quartz/CronTrigger);
    private String name;
    private String group;
    private JobDetail jobDetail;//job
    private JobDataMap jobDataMap;
    private Date startTime;
    private long startDelay;
    private String cronExpression;
    private TimeZone timeZone;
    private String calendarName;
    private int priority;
    private int misfireInstruction;
    private String description;
    private String beanName;
    private CronTrigger cronTrigger;
}

//CronTrigger实现类
public class CronTriggerImpl extends AbstractTrigger
    implements CronTrigger, CoreTrigger
{
    private static final long serialVersionUID = -8644953146451592766L;
    protected static final int YEAR_TO_GIVEUP_SCHEDULING_AT;
    private CronExpression cronEx;
    private Date startTime;
    private Date endTime;
    private Date nextFireTime;
    private Date previousFireTime;
    private transient TimeZone timeZone;

    static 
    {
        YEAR_TO_GIVEUP_SCHEDULING_AT = CronExpression.MAX_YEAR;
    }
}

总结:
JobDetailFactoryBean是通过jobDetails属性来生产job;
MethodInvokingJobDetailFactoryBean内置静态类MethodInvokingJob,
而MethodInvokingJob继承了QuartzJobBean,同时与一个内部变量MethodInvoker;
在MethodInvokingJobDetailFactoryBean属性初始化完后,通过MethodInvoker封装TargetObject的TargetMethod方法并在executeInternal中调用MethodInvoker.invoke()来生产job。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics