Java 程序员最喜欢的就是造轮子了,后端开发中时常要自己造一些轮子,一个工具包、封装一些开源组件、功能定制化等等,太常见了。
在 Spring 的自造轮子最常见的莫过于设计个注解,然后扫描到后在 BeanPostProcessor
中处理该注解对象,并根据注解组装一个新的对象然后注册到 Spring 中。
场景如《Quartz 动态调度 Job》所述那样,现在对文中 @ScheduledJob
注解的实现做详细说明。
@ScheduledJob
注解实现
1. 注解声明
我们需要支持 Quartz
的 Job 中常用的几个属性的配置,如任务的名字、任务分组和任务触发执行的时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ScheduledJob { String name();
String group() default QuartzConstants.DEFAULT_GROUP;
String cronExp(); }
|
注解在 ScheduledJob
上的 @Component
是 Spring 的元注解,该注解的作用相当于使 ScheduledJob
也像 Component
注解一样使类自动被 Spring 发现。
2. 处理注解类
新建一个 BeanPostProcessor
接口的实现类,对有 @ScheduledJob
注解的 bean 进行处理,相类逻辑主要实现在 postProcessAfterInitialization
中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class QuartzJobAutoDiscovery implements BeanPostProcessor {
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { val annotation = AnnotationUtils.findAnnotation(bean.getClass(), ScheduledJob.class); val targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (annotation != null) { if (!Job.class.isAssignableFrom(targetClass)) return bean;
Map<String, Object> jobData = null;
if (AbstractJob.class.isAssignableFrom(targetClass)) { AbstractJob job = (AbstractJob)bean;
jobData = job.getInitialJobData(); }
val name = annotation.name(); val group = annotation.group(); val cronExp = annotation.cronExp();
val job = QuartzUtils.createJobDetail(name, group, targetClass); val trigger = QuartzUtils.createTrigger(QuartzUtils.wrapTriggerName(name), QuartzUtils.wrapTriggerName(group), job.getKey(), cronExp, jobData);
try { this.beanFactory.registerSingleton(name, job); this.beanFactory.registerSingleton(QuartzUtils.wrapTriggerName(name), trigger); } catch (IllegalStateException e) { } }
return bean; } }
|
上述代码中使用了 ConfigurableBeanFactory
的 registerSingleton
来动态将对象注册到 Spring 中,我们需要实现 BeanFactoryAware
类,让 Spring 给我们注入 BeanFactory
实例。
1 2 3 4 5 6 7 8 9 10 11 12
| public class QuartzJobAutoDiscovery implements BeanPostProcessor, BeanFactoryAware { private ConfigurableBeanFactory beanFactory;
@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } } }
|
总体思路就是通过手动构造 Quartz 需要的 JobDetail
和 Trigger
对象并注册到 Spring 中,Quartz 初始化后调度器通过 Spring 取到这些对象进行管理。