转自 http://blog.arganzheng.me/posts/quartz-and-spring-integration-ioc-autowire.html
Quartz与Spring的整合-Quartz中的job如何自动注入spring容器托管的对象
问题
Quartz中的job是由Quartz框架动态创建的(配置该job的classname,通过反射创建),而job一般会依赖到配置在spring中的bean,怎样获取或者更好的自动注入这些依赖bean呢?
预期效果
我们希望达到这样的效果:
/**
*
* 取消超时未支付订单的任务。
*
* @author arganzheng
*/
public class CancelUnpaidOrderTask implements Job {
@Autowired
private AppOrderService orderService;
@Override
public void execute(JobExecutionContext ctx) throws JobExecutionException {
...
}
关键在这一行:
@Autowired
private AppOrderService orderService;
orderService是配置在spring容器中的,而CancelUnpaidOrderTask则是配置在Quartz数据库中,由org.springframework.scheduling.quartz.SpringBeanJobFactory
运行时调用`
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception;` 方法创建的。
解决方案
Spring提供了一种机制让你可以获取ApplicationContext。就是ApplicationContextAware
接口。对于一个实现了ApplicationContextAware
接口的类,Spring会实例化它的同时,调用它的public void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
接口,将该bean所属上下文传递给它。
一般利用这个来做ServicesLocator:
public class FooServicesLocator implemnts ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static FooService getFooService() {
return applicationContext.getBean(FooService.class);
}
}
当然,你需要在你的xml配置文件中定义FooServicesLocator和FooService。然后在需要引用FooService的地方,就可以这样子获取FooService了:FooServicesLocator.getFoobarServic();
得到Spring托管的FooService。
不过这样是依赖查询,不是注入,要实现DI,可以使用AutowireCapableBeanFactory
进行autowire。
applicationContext.getAutowireCapableBeanFactory().autowireBean(existingBean);
于是对于上面的那个问题,就有了如下的解决方案:
package me.arganzheng.study.quartz.task.SpringBeanJobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 自定义SpringBeanJobFactory,用于对Job注入ApplicationContext等。
*
* @author arganzheng
*/
public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.SpringBeanJobFactory implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 这里我们覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
applicationContext.getAutowireCapableBeanFactory().autowireBean(jobInstance);
return jobInstance;
}
}
然后在Spring中配置Quartz的入口:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class="me.arganzheng.study.quartz.task.SpringBeanJobFactory" />
</property>
...
</bean>
</beans>
对于数据库配置方式的Quartz,配置非常简单,就一个入口类org.springframework.scheduling.quartz.SchedulerFactoryBean
。我们这里通过配置它的jobFactory为我们自定义的JobFactory来实现自动注入功能:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class=”me.arganzheng.study.quartz.task.SpringBeanJobFactory" />
</property>
...
</bean>
注意 :上面的XML配置采用了直接配置jobFactory属性的方式将jobFactory配置为我们自定义的jobFactory类,默认是org.springframework.scheduling.quartz.SpringBeanJobFactory
。虽然Quartz允许我们通过org.quartz.scheduler.jobFactory.class
配置项配置自定义的jobFactory:
org.quartz.scheduler.jobFactory.class
The class name of the JobFactory to use. The default is
org.quartz.simpl.SimpleJobFactory
, you may like to tryorg.quartz.simpl.PropertySettingJobFactory
. A JobFatcory is responsible for producing instances of JobClasses. SimpleJobFactory simply calls newInstance() on the class. PropertySettingJobFactory does as well, but also reflectively sets the job’s bean properties using the contents of the JobDataMap.
但是注意到我们配置的是Spring封装的是org.springframework.scheduling.quartz.SchedulerFactoryBean
,它并不认这个配置项目。因为它已经将它的jobFactory由org.quartz.simpl.SimpleJobFactory
改为org.springframework.scheduling.quartz.SpringBeanJobFactory
,所以只能采用配置jobFactory属性的方式修改jobFactory为我们的自定义factory。
spring的AutowireCapableBeanFactory其实非常强大,Spring3.0允许任何通过Spring配置的bean都可以自动注入它所属的上下文,也就是说默认所有的bean都自动实现了ApplicationContextAware接口,这样就不用显示实现ApplicationContextAware接口了( 是不是更POJO:) ): How to inject dependencies into a self-instantiated object in Spring?
public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.SpringBeanJobFactory{
@Autowire
private AutowireCapableBeanFactory beanFactory;
/**
* 这里我们覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
beanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
关于使用ApplicationContextAware
和AutowireCapableBeanFactory
实现@Autowired功能,在stackoverflow上这个帖子有很详细的说明,可以参考一下:How to get beans created by FactoryBean spring managed?
其他解决方案
对于Quartz与Spring的整合问题,spring其实提供了很多内建方案:
- 使用
org.springframework.scheduling.quartz.JobDetailBean
+jobDataAsMap
:比如这个:Spring 3 + Quartz 1.8.6 Scheduler Example。不过貌似不推荐. - 使用
org.springframework.scheduling.quartz.SchedulerFactoryBean
+schedulerContextAsMap
:比如这个:Quartz and Spring Integration。 - 使用
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
:这个可以让任何定义在spring中的类成为Quartz要求的job。比如这个:25.6 Using the OpenSymphony Quartz Scheduler - 使用
org.springframework.scheduling.quartz.SchedulerFactoryBean
+applicationContextSchedulerContextKey
:比如这个:Accessing Spring beans from Quartz jobs
每种方法笔者都认真的看过,而且找的例子都是非常不错的例子。个人感觉3和4不错,尤其是4。3使用起来有点像spring的事务配置,4使用起来有点像在web层通过WebApplicationContextUtils
得到spring的ApplicationContext
。不过这几种方式都不是依赖注入,而且配置信息比较多。所以还是推荐上面的org.springframework.scheduling.quartz.SchedulerFactoryBean
+AutowireCapableBeanFactory的SpringBeanJobFactory
解决方案:)
@Autowired
注解大大节省了Spring的xml配置,将bean依赖关系声明转移到类文件和运行期。即: 原来需要这样的配置:
<bean id="thisClass" class="me.arganzheng.study.MyClass" />
<property name="anotherClass" ref="anotherClass" />
</bean>
<bean id="anotherClass" class="me.arganzheng.study.AnotherClass">
</bean>
package me.arganzheng.study;
public class MyClass {
private Another anotherClass;
public void setAnotherClass(AnotherClass anotherClass) {
this.anotherClass = anotherClass;
}
}
使用@Autowired
注解可以简化为:
<bean id="thisClass" class="me.arganzheng.study.MyClass" />
</bean>
<bean id="anotherClass" class="me.arganzheng.study.AnotherClass">
</bean>
package me.arganzheng.study;
public class MyClass {
@Autowired
private Another anotherClass;
}
不过这样MyClass本身在Spring配置文件中定义,而它的依赖又是在自身类文件通过@Autowired
注解声明,需要有种方式告诉Spring说当你根据配置文件创建我的时候,麻烦也扫描一下我的注解,把通过注解声明的依赖也注入进来。这可以通过Spring的<context:spring-configured/>
配置+AspectJ的 Configurable
注解来实现运行期依赖注入:Aspect Oriented Programming with Spring
@Configurable public class MyClass { @Autowired private AnotherClass instance; }
Then at creation time it will automatically inject its dependencies. You also should have
<context:spring-configured/>
in your application context xml. 说明:其实还需要MyClass注册在application context xml文件中。
不用AspectJ的注解,其实Spring3也有类似的注解,主要用于Spring MVC:
注意 :这里面有一个非常重要的前提,就是所有的类(如上面的MyClass
和AnotherClass
)都必须已经在spring中配置,只是这些bean直接的依赖关系(如上面的MyClass
依赖于AntherClass
),可以通过注解(如@autowired
)实现运行期自动注入。而且要让spring在根据配置文件创建该这些bean的时候,还额外的去解析该bean的注解并且注入通过注解声明的依赖bean,需要在配置文件中额外的配置来告诉spring。比如上面的<context:spring-configured/>
就是做这样的事情。
一个完整的Configurable例子见这篇文档:Spring, Aspects, @Configurable and Compile Time Weaving using maven
如果bean本身(不即使依赖关系)也不想使用Spring配置文件注册,那么就需要额外的配置告诉Spring哪些类是需要你托管的,一般是包扫描:<context:component-scan>
+特殊的类注解如@Controller,@Component, etc. 15. Web MVC framework-15.3.1 Defining a controller with @Controller:
15.3.1 Defining a controller with @Controller
The @Controller annotation indicates that a particular class serves the role of a controller. Spring does not require you to extend any controller base class or reference the Servlet API. However, you can still reference Servlet-specific features if you need to.
The @Controller annotation acts as a stereotype for the annotated class, indicating its role. The dispatcher scans such annotated classes for mapped methods and detects @RequestMapping annotations (see the next section).
You can define annotated controller beans explicitly, using a standard Spring bean definition in the dispatcher’s context. However, the @Controller stereotype also allows for autodetection, aligned with Spring general support for detecting component classes in the classpath and auto-registering bean definitions for them.
To enable autodetection of such annotated controllers, you add component scanning to your configuration. Use the spring-context schema as shown in the following XML snippet:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="org.springframework.samples.petclinic.web"/> // ... </beans>
stackoverflow上有一个非常详细讲解<context:annotation-config>
和<context:component-scan>
的帖子: Difference between <context:annotation-config> vs <context:component-scan>。很长,这里就不quote了。简单来说就是两个步骤:
- 扫描类:
<context:component-scan>
+@Controller
,@Component
, etc. - 通过注解方式注入该类的依赖:
<context:annotation-config/>
如果配置了1,那么自动包含2.
当然,回到我们的主题,如果有些bean不应该由Spring托管(不是xml配置,也不是anotation注解+包路径扫描),而是由框架或者应用创建的,那么就需要使用我们一开始介绍的方法来处理了。
—EOF—
相关推荐
4. 配置 Spring:在 `applicationContext.xml` 中定义 Job 和 Trigger 的 Bean,使用 Spring 的 `QuartzJobBean` 来托管 Job,然后定义 Trigger 来指定 Job 的执行时机。 5. 初始化 Quartz:在 `web.xml` 中添加一个...
基于的手势识别系统可控制灯的亮_3
untitled2.zip
S7-1500和分布式外围系统ET200MP模块数据
anaconda配置pytorch环境
高校教室管理系统,主要的模块包括查看首页、个人中心、教师管理、学生管理、教室信息管理、教师申请管理、学生申请管理、课时表管理、教师取消预约管理、学生取消预约管理等功能。
半挂汽车列车横向稳定性控制研究:基于模糊PID与制动力矩分配的联合仿真分析在典型工况下的表现,半挂汽车列车在典型工况下的横向稳定性控制研究:基于模糊PID与制动力矩分配的联合仿真分析,半挂汽车列车4自由度6轴整车model,横向稳定性控制,在低附着系数路面,进行典型3个工况,角阶跃,双移线,方向盘转角。 采用算法:模糊PID,制动力矩分配,最优滑移率滑膜控制。 以上基于trucksim和simulink联合仿真,有对应 p-a-p-e-r参考 ,关键词: 1. 半挂汽车列车 2. 4自由度6轴整车model 3. 横向稳定性控制 4. 低附着系数路面 5. 典型工况(角阶跃、双移线、方向盘转角) 6. 模糊PID算法 7. 制动力矩分配 8. 最优滑移率滑膜控制 9. Trucksim和Simulink联合仿真 10. P-A-P-E-R参考; 用分号隔开上述关键词为:半挂汽车列车; 4自由度6轴整车model; 横向稳定性控制; 低附着系数路面; 典型工况; 模糊PID算法; 制动力矩分配; 最优滑移率滑膜控制; Trucksim和Simulink联合仿真; P-A-P-E-R参考
路径规划人工势场法及其改进算法Matlab代码实现,路径规划人工势场法及其改进算法Matlab代码实现,路径规划人工势场法以及改进人工势场法matlab代码,包含了 ,路径规划; 人工势场法; 改进人工势场法; MATLAB代码; 分隔词“;”。,基于Matlab的改进人工势场法路径规划算法研究
本文介绍了范德堡大学深脑刺激器(DBS)项目,该项目旨在开发和临床评估一个系统,以辅助从规划到编程的整个过程。DBS是一种高频刺激治疗,用于治疗运动障碍,如帕金森病。由于目标区域在现有成像技术中可见性差,因此DBS电极的植入和编程过程复杂且耗时。项目涉及使用计算机辅助手术技术,以及一个定制的微定位平台(StarFix),该平台允许在术前进行图像采集和目标规划,提高了手术的精确性和效率。此外,文章还讨论了系统架构和各个模块的功能,以及如何通过中央数据库和网络接口实现信息共享。
三菱FX3U步进电机FB块的应用:模块化程序实现电机换算,提高稳定性和移植性,三菱FX3U步进电机换算FB块:模块化编程实现电机控制的高效性与稳定性提升,三菱FX3U 步进电机算FB块 FB块的使用可以使程序模块化简单化,进而提高了程序的稳定性和可移植性。 此例中使用FB块,可以实现步进电机的算,已知距离求得脉冲数,已知速度可以求得频率。 程序中包含有FB和ST内容;移植方便,在其他程序中可以直接添加已写好的FB块。 ,三菱FX3U;步进电机换算;FB块;程序模块化;稳定性;可移植性;距离与脉冲数换算;速度与频率换算;FB和ST内容;移植方便。,三菱FX3U步进电机换算FB块:程序模块化与高稳定性实现
光伏逆变器TMS320F28335设计方案:Boost升压与单相全桥逆变,PWM与SPWM控制,MPPT恒压跟踪法实现,基于TMS320F28335DSP的光伏逆变器设计方案:Boost升压与单相全桥逆变电路实现及MPPT技术解析,光伏逆变器设计方案TMS320F28335-176资料 PCB 原理图 源代码 1. 本设计DC-DC采用Boost升压,DCAC采用单相全桥逆变电路结构。 2. 以TI公司的浮点数字信号控制器TMS320F28335DSP为控制电路核心,采用规则采样法和DSP片内ePWM模块功能实现PWM和SPWM波。 3. PV最大功率点跟踪(MPPT)采用了恒压跟踪法(CVT法)来实现,并用软件锁相环进行系统的同频、同相控制,控制灵活简单。 4.资料包含: 原理图,PCB(Protel或者AD打开),源程序代码(CCS打开),BOM清单,参考资料 ,核心关键词:TMS320F28335-176; 光伏逆变器; 升压; 逆变电路; 数字信号控制器; 规则采样法; ePWM模块; PWM; SPWM波; MPPT; 恒压跟踪法; 原理图; PCB; 源程序代码; BOM
centos9内核安装包
昆仑通态触摸屏与两台台达VFD-M变频器通讯实现:频率设定、启停控制与状态指示功能接线及设置说明,昆仑通态TPC7062KD触摸屏与两台台达VFD-M变频器通讯程序:实现频率设定、启停控制与状态指示,昆仑通态MCGS与2台台达VFD-M变频器通讯程序实现昆仑通态触摸屏与2台台达VFD-M变频器通讯,程序稳定可靠 器件:昆仑通态TPC7062KD触摸屏,2台台达VFD-M变频器,附送接线说明和设置说明 功能:实现频率设定,启停控制,实际频率读取等,状态指示 ,昆仑通态MCGS; 台达VFD-M变频器; 通讯程序; 稳定可靠; 频率设定; 启停控制; 实际频率读取; 状态指示; 接线说明; 设置说明,昆仑通态MCGS与台达VFD-M变频器通讯程序:稳定可靠,双机控制全实现
研控步进电机驱动器方案验证通过,核心技术成熟可生产,咨询优惠价格!硬件原理图与PCB源代码全包括。,研控步进电机驱动器方案验证通过,核心技术掌握,生产准备,咨询实际价格,包含硬件原理图及PCB源代码。,研控步进电机驱动器方案 验证可用,可以生产,欢迎咨询实际价格,快速掌握核心技术。 包括硬件原理图 PCB源代码 ,研控步进电机驱动器方案; 验证可用; 可生产; 核心技术; 硬件原理图; PCB源代码,研控步进电机驱动器方案验证通过,现可生产供应,快速掌握核心技术,附硬件原理图及PCB源代码。
高质量的OPCClient_UA源码分享:基于C#的OPC客户端开发源码集(测试稳定、多行业应用实例、VS编辑器支持),高质量OPC客户端源码解析:OPCClient_UA C#开发,适用于VS2019及多行业现场应用源码分享,OPCClient_UA源码OPC客户端源码(c#开发) 另外有opcserver,opcclient的da,ua版本的见其他链接。 本项目为VS2019开发,可用VS其他版本的编辑器打开项目。 已应用到多个行业的几百个应用现场,长时间运行稳定,可靠。 本项目中提供测试OPCClient的软件开发源码,有详细的注释,二次开发清晰明了。 ,OPCClient_UA; OPC客户端源码; C#开发; VS2019项目; 稳定可靠; 详细注释; 二次开发,OPC客户端源码:稳定可靠的C#开发实现,含详细注释支持二次开发
毕业设计
三菱FX3U六轴标准程序:六轴控制特色及转盘多工位流水作业功能实现,三菱FX3U六轴标准程序:实现3轴本体控制与3个1PG定位模块,轴点动控制、回零控制及定位功能,结合气缸与DD马达控制转盘的多工位流水作业模式,三菱FX3U六轴标准程序,程序包含本体3轴控制,扩展3个1PG定位模块,一共六轴。 程序有轴点动控制,回零控制,相对定位,绝对定位。 另有气缸数个,一个大是DD马达控制的转盘,整个是转盘多工位流水作业方式 ,三菱FX3U;六轴控制;轴点动控制;回零控制;定位模块;DD马达转盘;流水作业方式,三菱FX3U六轴程序控制:转盘流水作业的机械多轴系统
在 GEE(Google Earth Engine)中,XEE 包是一个用于处理和分析地理空间数据的工具。以下是对 GEE 中 XEE 包的具体介绍: 主要特性 地理数据处理:提供强大的函数和工具,用于处理遥感影像和其他地理空间数据。 高效计算:利用云计算能力,支持大规模数据集的快速处理。 可视化:内置可视化工具,方便用户查看和分析数据。 集成性:可以与其他 GEE API 和工具无缝集成,支持多种数据源。 适用场景 环境监测:用于监测森林砍伐、城市扩展、水体变化等环境问题。 农业分析:分析作物生长、土地利用变化等农业相关数据。 气候研究:研究气候变化对生态系统和人类活动的影响。
基于博途V16的邮件分拣机控制系统设计与实现:西门子S7-1200PLC与TP700触摸屏程序化及其仿真视频与CAD接线控制要求详解。,邮件分拣机自动化系统设计与实现:基于西门子S7-1200PLC与TP700触摸屏的博途V16程序,包含仿真视频、CAD接线及控制要求详解。,邮件分拣机控制系统西门子S7-1200PLC和TP700触摸屏程序博途V16,带仿真视频CAD接线和控制要求 ,邮件分拣; 控制系统; 西门子S7-1200PLC; TP700触摸屏程序; 博途V16; 仿真视频; CAD接线; 控制要求,邮件分拣机控制系统:S7-1200PLC与TP700触摸屏程序博途V16集成仿真视频CAD控制要求