springboot和quartz整合实现动态定时任务(持久化单节点)
Quartz是一个完全由java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制,它支持定时任务持久化到数据库,从而避免了重启服务器时任务丢失,支持分布式多节点,大大的提高了单节点定时任务的容错性。springboot在2.0版本以前没有对quartz做自动配置,因此需要我们自己去手动配置,网上找了许多资料,但是大都不能完全满足自己的需要,因此自己整合了一下方便以后参考(copy),整合代码基于springboot1.5.9和quartz2.3.0,过程如下:
1、pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>powerx.io</groupId>
- <artifactId>springboot-quartz</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>springboot-quartz</name>
- <description>Demo project for Spring Boot</description>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.9.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- <druid.version>1.1.5</druid.version>
- <quartz.version>2.3.0</quartz.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>${druid.version}</version>
- </dependency>
- <!--quartz相关依赖-->
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz</artifactId>
- <version>${quartz.version}</version>
- </dependency>
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz-jobs</artifactId>
- <version>${quartz.version}</version>
- </dependency>
- <!--定时任务需要依赖context模块-->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
2、整合配置类
采用jobDetail
使用Spring Ioc
托管方式来完成整合,我们可以在定时任务实例中使用Spring
注入注解完成业务逻辑处理,代码如下
- package com.example.demo.config;
- import org.quartz.spi.JobFactory;
- import org.quartz.spi.TriggerFiredBundle;
- import org.springframework.beans.factory.annotation.Autowire;
- import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.io.ClassPathResource;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.quartz.SchedulerFactoryBean;
- import org.springframework.scheduling.quartz.SpringBeanJobFactory;
- import javax.sql.DataSource;
- @Configuration
- @EnableScheduling
- public class QuartzConfiguration {
- /**
- * 继承org.springframework.scheduling.quartz.SpringBeanJobFactory
- * 实现任务实例化方式
- */
- public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
- ApplicationContextAware {
- private transient AutowireCapableBeanFactory beanFactory;
- @Override
- public void setApplicationContext(final ApplicationContext context) {
- beanFactory = context.getAutowireCapableBeanFactory();
- }
- /**
- * 将job实例交给spring ioc托管
- * 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
- *
- * @param bundle
- * @return
- * @throws Exception
- */
- @Override
- protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
- final Object job = super.createJobInstance(bundle);
- /**
- * 将job实例交付给spring ioc
- */
- beanFactory.autowireBean(job);
- return job;
- }
- }
- /**
- * 配置任务工厂实例
- *
- * @return
- */
- @Bean
- public JobFactory jobFactory() {
- /**
- * 采用自定义任务工厂 整合spring实例来完成构建任务*/
- AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
- return jobFactory;
- }
- /**
- * 配置任务调度器
- * 使用项目数据源作为quartz数据源
- *
- * @param jobFactory 自定义配置任务工厂
- * @param dataSource 数据源实例
- * @return
- * @throws Exception
- */
- @Bean(destroyMethod = "destroy", autowire = Autowire.NO)
- public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception {
- SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
- //将spring管理job自定义工厂交由调度器维护
- schedulerFactoryBean.setJobFactory(jobFactory);
- //设置覆盖已存在的任务
- schedulerFactoryBean.setOverwriteExistingJobs(true);
- //项目启动完成后,等待2秒后开始执行调度器初始化
- schedulerFactoryBean.setStartupDelay(2);
- //设置调度器自动运行
- schedulerFactoryBean.setAutoStartup(true);
- //设置数据源,使用与项目统一数据源
- schedulerFactoryBean.setDataSource(dataSource);
- //设置上下文spring bean name
- schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
- //设置配置文件位置
- schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
- return schedulerFactoryBean;
- }
- }
AutowiringSpringBeanJobFactory:可以看到上面配置类中,AutowiringSpringBeanJobFactory
我们继承了SpringBeanJobFactory
类,并且通过实现ApplicationContextAware
接口获取ApplicationContext
设置方法,通过外部实例化时设置ApplicationContext
实例对象,在createJobInstance
方法内,我们采用AutowireCapableBeanFactory
来托管SpringBeanJobFactory
类中createJobInstance
方法返回的定时任务实例,这样我们就可以在定时任务类内使用Spring Ioc
相关的注解进行注入业务逻辑实例了。
JobFactory:自定义任务工厂
SchedulerFactoryBean:使用项目内部数据源的方式来设置调度器的jobSotre
,官方quartz
有两种持久化的配置方案。
第一种:采用quartz.properties
配置文件配置独立的定时任务数据源,可以与使用项目的数据库完全独立。
第二种:采用与创建项目统一个数据源,定时任务持久化相关的表与业务逻辑在同一个数据库内。
可以根据实际的项目需求采取不同的方案,我采用了第二种方案,在上面配置类中可以看到方法schedulerFactoryBean
内自动注入了JobFactory
实例,也就是我们自定义的AutowiringSpringBeanJobFactory
任务工厂实例,另外一个参数就是DataSource
,在我们引入spring-boot-starter-jdbc依赖后会根据application.yml
文件内的数据源相关配置自动实例化DataSource
实例,这里直接注入是没有问题的。我们通过调用SchedulerFactoryBean
对象的setConfigLocation
方法来设置quartz
定时任务框架的基本配置,配置文件所在位置:resources/quartz.properties
=> classpath:/quartz.properties
下。
quartz.properties内容如下:
- org.quartz.scheduler.instanceName = schedulerFactoryBean
- org.quartz.scheduler.instanceId = AUTO
- org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
- org.quartz.jobStore.tablePrefix = QRTZ_
- org.quartz.jobStore.useProperties = false
- org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
- org.quartz.threadPool.threadCount = 10
- org.quartz.threadPool.threadPriority = 5
在上面配置中org.quartz.jobStore.class
与org.quartz.jobStore.driverDelegateClass
是定时任务持久化的关键配置,配置了数据库持久化定时任务以及采用MySQL
数据库进行连接,当然你也可以连接别的数据库org.quartz.jobStore.tablePrefix
属性配置了定时任务数据表的前缀,在quartz
官方提供的创建表SQL脚本
默认就是qrtz_,我们需要解压quartz2.3.0的jar,在quartz-2.2.3/docs/dbTables下找到tables_mysql_innodb.sql,然后在mysql客户端执行来创建相应的表。
3、动态定时任务demo
QuartzService.java
- package com.example.demo.service;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.annotation.PostConstruct;
- import org.quartz.CronScheduleBuilder;
- import org.quartz.CronTrigger;
- import org.quartz.DateBuilder;
- import org.quartz.DateBuilder.IntervalUnit;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobKey;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.quartz.SimpleScheduleBuilder;
- import org.quartz.Trigger;
- import org.quartz.TriggerBuilder;
- import org.quartz.TriggerKey;
- import org.quartz.impl.matchers.GroupMatcher;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- import org.springframework.stereotype.Service;
- @Service
- public class QuartzService {
- @Autowired
- private Scheduler scheduler;
- @PostConstruct
- public void startScheduler() {
- try {
- scheduler.start();
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 增加一个job
- *
- * @param jobClass
- * 任务实现类
- * @param jobName
- * 任务名称
- * @param jobGroupName
- * 任务组名
- * @param jobTime
- * 时间表达式 (这是每隔多少秒为一次任务)
- * @param jobTimes
- * 运行的次数 (<0:表示不限次数)
- */
- public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, int jobTime,
- int jobTimes) {
- try {
- JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)// 任务名称和组构成任务key
- .build();
- // 使用simpleTrigger规则
- Trigger trigger = null;
- if (jobTimes < 0) {
- trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
- .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
- .startNow().build();
- } else {
- trigger = TriggerBuilder
- .newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder
- .repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
- .startNow().build();
- }
- scheduler.scheduleJob(jobDetail, trigger);
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 增加一个job
- *
- * @param jobClass
- * 任务实现类
- * @param jobName
- * 任务名称
- * @param jobGroupName
- * 任务组名
- * @param jobTime
- * 时间表达式 (如:0/5 * * * * ? )
- */
- public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobTime) {
- try {
- // 创建jobDetail实例,绑定Job实现类
- // 指明job的名称,所在组的名称,以及绑定job类
- JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)// 任务名称和组构成任务key
- .build();
- // 定义调度触发规则
- // 使用cornTrigger规则
- Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)// 触发器key
- .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
- .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();
- // 把作业和触发器注册到任务调度中
- scheduler.scheduleJob(jobDetail, trigger);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 修改 一个job的 时间表达式
- *
- * @param jobName
- * @param jobGroupName
- * @param jobTime
- */
- public void updateJob(String jobName, String jobGroupName, String jobTime) {
- try {
- TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
- CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
- trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
- .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
- // 重启触发器
- scheduler.rescheduleJob(triggerKey, trigger);
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 删除任务一个job
- *
- * @param jobName
- * 任务名称
- * @param jobGroupName
- * 任务组名
- */
- public void deleteJob(String jobName, String jobGroupName) {
- try {
- scheduler.deleteJob(new JobKey(jobName, jobGroupName));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 暂停一个job
- *
- * @param jobName
- * @param jobGroupName
- */
- public void pauseJob(String jobName, String jobGroupName) {
- try {
- JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
- scheduler.pauseJob(jobKey);
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 恢复一个job
- *
- * @param jobName
- * @param jobGroupName
- */
- public void resumeJob(String jobName, String jobGroupName) {
- try {
- JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
- scheduler.resumeJob(jobKey);
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 立即执行一个job
- *
- * @param jobName
- * @param jobGroupName
- */
- public void runAJobNow(String jobName, String jobGroupName) {
- try {
- JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
- scheduler.triggerJob(jobKey);
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- }
- /**
- * 获取所有计划中的任务列表
- *
- * @return
- */
- public List<Map<String, Object>> queryAllJob() {
- List<Map<String, Object>> jobList = null;
- try {
- GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
- Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
- jobList = new ArrayList<Map<String, Object>>();
- for (JobKey jobKey : jobKeys) {
- List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
- for (Trigger trigger : triggers) {
- Map<String, Object> map = new HashMap<>();
- map.put("jobName", jobKey.getName());
- map.put("jobGroupName", jobKey.getGroup());
- map.put("description", "触发器:" + trigger.getKey());
- Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
- map.put("jobStatus", triggerState.name());
- if (trigger instanceof CronTrigger) {
- CronTrigger cronTrigger = (CronTrigger) trigger;
- String cronExpression = cronTrigger.getCronExpression();
- map.put("jobTime", cronExpression);
- }
- jobList.add(map);
- }
- }
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- return jobList;
- }
- /**
- * 获取所有正在运行的job
- *
- * @return
- */
- public List<Map<String, Object>> queryRunJob() {
- List<Map<String, Object>> jobList = null;
- try {
- List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
- jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
- for (JobExecutionContext executingJob : executingJobs) {
- Map<String, Object> map = new HashMap<String, Object>();
- JobDetail jobDetail = executingJob.getJobDetail();
- JobKey jobKey = jobDetail.getKey();
- Trigger trigger = executingJob.getTrigger();
- map.put("jobName", jobKey.getName());
- map.put("jobGroupName", jobKey.getGroup());
- map.put("description", "触发器:" + trigger.getKey());
- Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
- map.put("jobStatus", triggerState.name());
- if (trigger instanceof CronTrigger) {
- CronTrigger cronTrigger = (CronTrigger) trigger;
- String cronExpression = cronTrigger.getCronExpression();
- map.put("jobTime", cronExpression);
- }
- jobList.add(map);
- }
- } catch (SchedulerException e) {
- e.printStackTrace();
- }
- return jobList;
- }
- }
UserService.java
- package com.example.demo.service;
- import org.springframework.stereotype.Service;
- @Service
- public class UserService {
- public void play() {
- System.out.println("user id play");
- }
- public void study() {
- System.out.println("user id study");
- }
- }
TestJob1.java
- package com.example.demo.job;
- import java.util.Date;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- public class TestJob1 extends QuartzJobBean {
- @Override
- protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
- System.out.println(new Date() + " job执行");
- }
- }
TestJob2.java
- package com.example.demo.job;
- import java.util.Date;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- import org.springframework.stereotype.Component;
- import com.example.demo.service.UserService;
- @Component
- public class TestJob2 extends QuartzJobBean {
- //注入业务service,完成定时任务逻辑
- @Autowired
- private UserService service;
- @Override
- protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
- System.out.println(new Date() + " job2执行");
- service.play();
- }
- }
TestController.java
- package com.example.demo.controller;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import com.example.demo.job.TestJob1;
- import com.example.demo.job.TestJob2;
- import com.example.demo.service.QuartzService;
- @RestController
- public class TestController {
- @Autowired
- private QuartzService quartzService;
- @RequestMapping("/addjob")
- public void startJob(String type) {
- if("TestJob1".equals(type)) {
- quartzService.addJob(TestJob1.class, "job1", "test", "0/5 * * * * ?");
- }else {
- quartzService.addJob(TestJob2.class, "job2", "test", "0/5 * * * * ?");
- }
- }
- @RequestMapping("/updatejob")
- public void updatejob() {
- quartzService.updateJob("job1", "test", "0/10 * * * * ?");
- }
- @RequestMapping("/deletejob")
- public void deletejob() {
- quartzService.deleteJob("job1", "test");
- }
- @RequestMapping("/pauseJob")
- public void pauseJob() {
- quartzService.pauseJob("job1", "test");
- }
- @RequestMapping("/resumeJob")
- public void resumeJob() {
- quartzService.resumeJob("job1", "test");
- }
- @RequestMapping("/queryAllJob")
- public Object queryAllJob() {
- return quartzService.queryAllJob();
- }
- @RequestMapping("/queryRunJob")
- public Object queryRunJob() {
- return quartzService.queryRunJob();
- }
- }
4、application.yml
- spring:
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- driver-class-name: com.mysql.jdbc.Driver
- url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
- username: root
- password: root
- jpa:
- hibernate:
- ddl-auto: update #ddl-auto:设为update表示每次都不会重新建表
- show-sql: true
- application:
- name: quartz-cluster-node-first
- server:
- port: 8081
- # 打印日志
- logging:
- level:
- root: INFO
- org.hibernate: INFO
- org.hibernate.type.descriptor.sql.BasicBinder: TRACE
- org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
- com.springms: DEBUG
至此,springboot整合quartz实现动态定时任务和任务持久化完毕,各功能我都测试过,符合预期,具体结果不再贴出,小伙伴们在使用时要注意springboot和quartz的版本问题,很多时候并不是代码有问题,而是jar不匹配。springboot2.0以后,直接有了spring-boot-starter-quartz包,我们只需要把原来的jar替换掉,无需任何配置就完成了整合。
springboot和quartz整合实现动态定时任务(持久化单节点)的更多相关文章
- 在springBoot与quartz 整合中 @Transaction 失效
问题1::springBoot在与quartz 整合时,使用@Transaction 注解时事务失效 解决方案:创建一个类使用@component被spring管理 ,使用@Transaction标识 ...
- quartz spring 实现动态定时任务
在实际项目应用中经常会用到定时任务,可以通过quartz和spring的简单配置即可完成,但如果要改变任务的执行时间.频率,废弃任务等就需要改变配置甚至代码需要重启服务器,这里介绍一下如何通过quar ...
- springboot和quartz整合分布式多节点
虽然单个Quartz实例能给予我们很好的任务job调度能力,但它不能满足典型的企业需求,如可伸缩性.高可靠性满足.假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成为你应用的一 ...
- Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置
Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置 >>>>>>>>>>>>&g ...
- spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】
最近做了一个spring boot 整合 quartz 实现 动态定时任务配置,在集群环境下运行的 任务.能够对定时任务,动态的进行增删改查,界面效果图如下: 1. 在项目中引入jar 2. 将需要 ...
- Spring 整合 Quartz 实现动态定时任务
复制自:https://www.2cto.com/kf/201605/504659.html 最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能 ...
- 【转】Spring 整合 Quartz 实现动态定时任务
http://blog.csdn.net/u014723529/article/details/51291289 最近项目中需要用到定时任务的功能,虽然spring 也自带了一个轻量级的定时任务实现, ...
- Spring 整合 Quartz 实现动态定时任务(附demo)
最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之后,决定整合更为专业的Quartz来实现定时任务功能. 普通定时任务 首先 ...
- spring与quartz整合实现分布式动态创建,删除,改变执行时间定时任务(mysql数据库)
背景:因为在项目中用到了定时任务,当时想到了spring的quartz,写完发现费了很大功夫,光是整合就花了一上午,其中最大的问题就是版本问题,项目中用的是spring3.2.8的版本,查阅发现,3. ...
随机推荐
- How do I avoid capturing self in blocks when implementing an API?
Short answer Instead of accessing self directly, you should access it indirectly, from a reference t ...
- struts2的validate输入验证
原创 struts2的输入验证有两种方式: 使用validate()方法实现验证 使用验证文件实现验证 下面通过一个例子介绍validate()方法验证——实现客户注册输入验证 设计的JSP页面代码: ...
- java学习(七)java中抽象类及 接口
抽象类的特点: A:抽象类和抽象方法必须用abstract关键字修饰. B:抽象类中不一定有抽象方法,但是抽象方法的类必须定义为抽象类 c: 抽象类不能被实例化,因为它不是具体的. 抽象类有构造方法, ...
- Partition--分区切换
现有数据表[dbo].[staging_TB1_20131018-104722]和分区表[dbo].[TB1],需要将分区表和数据表中做数据交换 CREATE TABLE [dbo].[staging ...
- [HTTP]Nonocast.http post方法
Nonocast.Http is a free, open source developer focused web service via http for small and medium sof ...
- asp.net mvc项目创建WebApi简单例子
1.创建默认路由的映射. namespace RedisDemo.App_Start { public class WebApiConfig { public static void Register ...
- loadrunner 11问题汇总
1.问题描述:安装loadrunner11后,录制脚本时,explore未打开,event为0,录制结果为空.安装环境是window7+ie8+loadrunner11 解决方案: 1.首先要把ie设 ...
- Excel一对多查询(index+small+if)
一.学习 一对多查询模式化数组公式: =INDEX(区域,SMALL(IF(条件,行号数组,4^8),ROW(A1))) 三键齐按(ctrl+shift+回车) 在具有多个符合条件的情况下,提取和匹配 ...
- python 小点
python中列表不能除以列表,列表不能除以整数.浮点数. numpy数组可以实现数组除以整数.
- php面向对象编程_1
1, php面向对象编程的三大特征: (1) 封装性,封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法)才能对数据进行操作. (2) 继承 ...