生活随笔
收集整理的這篇文章主要介紹了
注解 @Scheduled
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
我們跑定時(shí)的時(shí)候,代碼的結(jié)構(gòu)大致是這個(gè)樣子的。
@Scheduled(cron="0?0?4?*?*??")
public?void?taskCycle()?{Calendar??cal??=??Calendar.getInstance();cal.add(Calendar.DATE,?-1);yesterday?=?new?SimpleDateFormat(?"yyyyMMdd").format(cal.getTime());//默認(rèn)5000int?height?=?Integer.valueOf("5000");//主頁(yè)heatMapDto?=?createZy("zhuye",height);createHotMap(heatMapDto);//我的賬戶heatMapDto?=?createZy("myacount",height);createHotMap(heatMapDto);LOGGER.info("今執(zhí)行了熱力圖定時(shí)任務(wù)"?+?yesterday);
}
那么,這個(gè)Scheduled(cron="0 0 4 * * ?")是如何被系統(tǒng)識(shí)別并且去跑定時(shí)任務(wù)呢?@Scheduled的解析器是ScheduledAnnotationBeanPostProcessor 該類實(shí)現(xiàn)了類BeanPostProcessor,這樣在容器啟動(dòng)的時(shí)候會(huì)在refresh()的時(shí)候調(diào)用到所有實(shí)現(xiàn)了BeanPostProcessor接口的類。如下:
AbstractBeanFactory (方法:createBean(beanName,?mbd,?args))--->AbstractAutowireCapableBeanFactory
(方法:createBean(final?String beanName,?final?RootBeanDefinition mbd,?final?Object[] args)) ---》AbstractAutowireCapableBeanFactory ?(方法:protected?Object?resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd))--》
protected?Object?resolveBeforeInstantiation(String?beanName,?RootBeanDefinition?mbd)?{Object?bean?=?null;if?(!Boolean.FALSE.equals(mbd.beforeInstantiationResolved))?{//?Make?sure?bean?class?is?actually?resolved?at?this?point.if?(mbd.hasBeanClass()?&&?!mbd.isSynthetic()?&&?hasInstantiationAwareBeanPostProcessors())?{//執(zhí)行BeanPostProcessor的applyBeanPostProcessorsBeforeInstantiation接口bean?=?applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(),?beanName);if?(bean?!=?null)?{//執(zhí)行BeanPostProcessor的applyBeanPostProcessorsBeforeInstantiation接口bean?=?applyBeanPostProcessorsAfterInitialization(bean,?beanName);}}mbd.beforeInstantiationResolved?=?(bean?!=?null);}return?bean;
} ---》AbstractAutowireCapableBeanFactory
public?Object?applyBeanPostProcessorsAfterInitialization(Object?existingBean,?String?beanName)throws?BeansException?{Object?result?=?existingBean;for?(BeanPostProcessor?beanProcessor?:?getBeanPostProcessors())?{//bean會(huì)走下每一個(gè)配置到系統(tǒng)中實(shí)現(xiàn)了接口BeanPostProcessor的類的postProcessAfterIn//itialization方法result?=?beanProcessor.postProcessAfterInitialization(result,?beanName);if?(result?==?null)?{return?result;}}return?result;
}
到此我們知道了接口實(shí)現(xiàn)類的實(shí)現(xiàn)時(shí)機(jī)。那么@Scheduled的解析器是ScheduledAnnotationBeanPostProcessor在執(zhí)行的時(shí)候又做了什么呢?讓我們來(lái)看看ScheduledAnnotationBeanPostProcessor的postProcessAfterInitialization方法是實(shí)現(xiàn)了什么。
public?Object?postProcessAfterInitialization(final?Object?bean,?String?beanName)?{
//獲取目標(biāo)類final?Class<?>?targetClass?=?AopUtils.getTargetClass(bean);//利用類反射為目標(biāo)類方法做回調(diào)函數(shù)ReflectionUtils.doWithMethods(targetClass,?new?MethodCallback()?{public?void?doWith(Method?method)?throws?IllegalArgumentException,?IllegalAccessException?{//首先判斷是否有@Scheduled標(biāo)簽Scheduled?annotation?=?AnnotationUtils.getAnnotation(method,?Scheduled.class);//如果有標(biāo)簽if?(annotation?!=?null)?{try?{//判斷返回類型是否為空??(Scheduled表示不允許有返回值)Assert.isTrue(void.class.equals(method.getReturnType()),"Only?void-returning?methods?may?be?annotated?with?@Scheduled");//Scheduled方法不允許有參數(shù)Assert.isTrue(method.getParameterTypes().length?==?0,"Only?no-arg?methods?may?be?annotated?with?@Scheduled");//判斷目標(biāo)類是否是jdk代理類if?(AopUtils.isJdkDynamicProxy(bean))?{try?{//?found?a?@Scheduled?method?on?the?target?class?for?this?JDK?proxy?->?is?it//?also?present?on?the?proxy?itself?method?=?bean.getClass().getMethod(method.getName(),?method.getParameterTypes());}catch?(SecurityException?ex)?{ReflectionUtils.handleReflectionException(ex);}catch?(NoSuchMethodException?ex)?{throw?new?IllegalStateException(String.format("@Scheduled?method?'%s'?found?on?bean?target?class?'%s',?"?+"but?not?found?in?any?interface(s)?for?bean?JDK?proxy.?Either?"?+"pull?the?method?up?to?an?interface?or?switch?to?subclass?(CGLIB)?"?+"proxies?by?setting?proxy-target-class/proxyTargetClass?"?+"attribute?to?'true'",?method.getName(),?targetClass.getSimpleName()));}}//生成一個(gè)定時(shí)器任務(wù)Runnable?runnable?=?new?ScheduledMethodRunnable(bean,?method);boolean?processedSchedule?=?false;String?errorMessage?=?"Exactly?one?of?the?'cron',?'fixedDelay(String)',?or?'fixedRate(String)'?attributes?is?required";//?Determine?initial?delay//首先實(shí)例化一個(gè)定時(shí)器延時(shí)時(shí)間?initialDelay?=-1long?initialDelay?=?annotation.initialDelay();//initialDelayString?=""String?initialDelayString?=?annotation.initialDelayString();if?(!"".equals(initialDelayString))?{Assert.isTrue(initialDelay?<?0,?"Specify?'initialDelay'?or?'initialDelayString',?not?both");if?(embeddedValueResolver?!=?null)?{initialDelayString?=?embeddedValueResolver.resolveStringValue(initialDelayString);}try?{initialDelay?=?Integer.parseInt(initialDelayString);}catch?(NumberFormatException?ex)?{throw?new?IllegalArgumentException("Invalid?initialDelayString?value?\""?+?initialDelayString?+?"\"?-?cannot?parse?into?integer");}}//獲取cron表達(dá)式0?*?*?*?*?*String?cron?=?annotation.cron();//檢查cron表達(dá)式非空if?(!"".equals(cron))?{Assert.isTrue(initialDelay?==?-1,?"'initialDelay'?not?supported?for?cron?triggers");processedSchedule?=?true;if?(embeddedValueResolver?!=?null)?{//解析cron表達(dá)式cron?=?embeddedValueResolver.resolveStringValue(cron);}//注冊(cè)定時(shí)任務(wù)registrar.addCronTask(new?CronTask(runnable,?cron));}//?At?this?point?we?don't?need?to?differentiate?between?initial?delay?set?or?not?anymoreif?(initialDelay?<?0)?{initialDelay?=?0;}//?Check?fixed?delay?fixedDelay?=-1long?fixedDelay?=?annotation.fixedDelay();if?(fixedDelay?>=?0)?{Assert.isTrue(!processedSchedule,?errorMessage);processedSchedule?=?true;registrar.addFixedDelayTask(new?IntervalTask(runnable,?fixedDelay,?initialDelay));}String?fixedDelayString?=?annotation.fixedDelayString();if?(!"".equals(fixedDelayString))?{Assert.isTrue(!processedSchedule,?errorMessage);processedSchedule?=?true;if?(embeddedValueResolver?!=?null)?{fixedDelayString?=?embeddedValueResolver.resolveStringValue(fixedDelayString);}try?{fixedDelay?=?Integer.parseInt(fixedDelayString);}catch?(NumberFormatException?ex)?{throw?new?IllegalArgumentException("Invalid?fixedDelayString?value?\""?+?fixedDelayString?+?"\"?-?cannot?parse?into?integer");}registrar.addFixedDelayTask(new?IntervalTask(runnable,?fixedDelay,?initialDelay));}//?Check?fixed?ratelong?fixedRate?=?annotation.fixedRate();if?(fixedRate?>=?0)?{Assert.isTrue(!processedSchedule,?errorMessage);processedSchedule?=?true;registrar.addFixedRateTask(new?IntervalTask(runnable,?fixedRate,?initialDelay));}String?fixedRateString?=?annotation.fixedRateString();if?(!"".equals(fixedRateString))?{Assert.isTrue(!processedSchedule,?errorMessage);processedSchedule?=?true;if?(embeddedValueResolver?!=?null)?{fixedRateString?=?embeddedValueResolver.resolveStringValue(fixedRateString);}try?{fixedRate?=?Integer.parseInt(fixedRateString);}catch?(NumberFormatException?ex)?{throw?new?IllegalArgumentException("Invalid?fixedRateString?value?\""?+?fixedRateString?+?"\"?-?cannot?parse?into?integer");}registrar.addFixedRateTask(new?IntervalTask(runnable,?fixedRate,?initialDelay));}//?Check?whether?we?had?any?attribute?setAssert.isTrue(processedSchedule,?errorMessage);}catch?(IllegalArgumentException?ex)?{throw?new?IllegalStateException("Encountered?invalid?@Scheduled?method?'"?+?method.getName()?+?"':?"?+?ex.getMessage());}}}});return?bean;
}
到此我們把定時(shí)任務(wù)注冊(cè)到了定時(shí)列表中了。那么定時(shí)列表是如何啟動(dòng)的呢?
ScheduledTaskRegistrar類實(shí)現(xiàn)了InitializingBean接口,在容器啟動(dòng)的時(shí)候?qū)崿F(xiàn)了該方法
public?void?afterPropertiesSet()?{
//定時(shí)任務(wù)啟動(dòng)???scheduleTasks();
}
定時(shí)任務(wù)都放到了List<ScheduledFuture>.該接口擴(kuò)展了延時(shí)隊(duì)列接口Delayed和異步接口Future。我們看一個(gè)ScheduledFuture的實(shí)現(xiàn)類。周期性的隊(duì)列其實(shí)就是在再延時(shí)隊(duì)列基礎(chǔ)上的。我們知道延時(shí)隊(duì)列能夠?qū)崿F(xiàn)在任務(wù)執(zhí)行時(shí)間到了的時(shí)候去執(zhí)行一次任務(wù)。而周期性隊(duì)列的任務(wù)就是將延時(shí)隊(duì)列的務(wù)執(zhí)行之后把它按照周期時(shí)間繼續(xù)放入到延時(shí)隊(duì)列中,等待下一個(gè)執(zhí)行時(shí)間到了繼續(xù)該循環(huán)操作。
轉(zhuǎn)載于:https://my.oschina.net/zjItLife/blog/533088
總結(jié)
以上是生活随笔為你收集整理的注解 @Scheduled的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。