要想获取使用指定注解的类信息,可借助工具:

org.reflections.Reflections

此工具将Java反射进行了高级封装,Reflections 通过扫描 classpath,索引元数据,允许在运行时查询这些元数据,也可以保存收集项目中多个模块的元数据信息。

使用 Reflections 可以查询以下元数据信息:

1)获得某个类型的所有子类型
2)获得标记了某个注解的所有类型/成员变量,支持注解参数匹配。
3)使用正则表达式获得所有匹配的资源文件
4)获得所有特定签名(包括参数,参数注解,返回值)的方法

Reflections 依赖 Google 的 Guava 库和 Javassist 库。

Maven引入方式:

<dependency><groupId>org.reflections</groupId><artifactId>reflections</artifactId><version>0.9.11</version>
</dependency>

sbt引入方式:

"org.reflections" % "reflections" % "0.9.11"

首先自定义注解:

package com.today.service.financetask.job
import java.lang.annotation.*;/*** 类功能描述:job 信息注解** @author WangXueXing create at 19-5-4 上午9:14* @version 1.0.0*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface JobInfo {/*** job id* @return*/String jobId();/*** job name* @return*/String jobName();/*** default cron* @return*/String defaultCron();
}

将某些类添加注解:

package com.today.service.financetask.job
import java.util.Calendarimport com.today.api.checkaccount.scala.CheckAccountServiceClient
import com.today.api.checkaccount.scala.enums.FlatFormTypeEnum
import com.today.api.checkaccount.scala.request.ReconciliationRequest
import com.today.service.financetask.job.define.AbstractJob
import com.today.service.financetask.utils.JobInfo
import org.quartz.JobExecutionContext/*** 自动对账*/
@JobInfo(jobId="CHECK_ACCOUNT_PROCESS", jobName="对账系统自动对账定时任务", defaultCron="0 0 13 * * ?")
class CheckAccountJob extends AbstractJob{/*** start up the scheduled task** @param context JobExecutionContext*/override def run(context: JobExecutionContext): Unit = {val cal = Calendar.getInstancecal.add(Calendar.DATE, -1)new CheckAccountServiceClient().appReconciliation(new ReconciliationRequest(FlatFormTypeEnum.TODAY_APP,None))}
}

import com.today.service.financetask.action.DailyStatementAction
import com.today.service.financetask.job.define.AbstractJob
import com.today.service.financetask.utils.JobInfo
import org.quartz.JobExecutionContext
import org.springframework.stereotype.Service/*** 日次处理定时任务处理** @author zhangc create at 2018/5/11 14:08* @version 0.0.1*/
@Service
@JobInfo(jobId="DAY_TIME_PROCESS", jobName="日次处理定时任务", defaultCron="0 30 2 * * ?")
class DayTimeProcessJob extends AbstractJob{/*** start up the scheduled task** @param context JobExecutionContext*/override def run(context: JobExecutionContext): Unit = {new DailyStatementAction().execute}
}

通过Java反射及Reflections工具类实现被JobInfo注解的所有类信息:

import java.utilimport com.today.service.financetask.utils.JobInfo
import org.quartz.Job
import org.reflections.Reflectionsimport scala.collection.JavaConverters._
import scala.collection.mutable/*** 通过注解获取所有通用Job信息** @author BarryWang create at 2018/5/12 10:45* @version 0.0.1*/
object JobEnum {/*** 获取添加JobInfo注解的类信息*/val jobWithAnnotation: util.Set[Class[_]] = new Reflections("com.today.service.financetask.job").getTypesAnnotatedWith(classOf[JobInfo])/*** 获取所有job枚举值* @return*/def values : mutable.Set[JobInfo] = jobWithAnnotation.asScala.map(getJobInfo(_))/*** 根据job class 获取job 信息* @param jobClass* @return*/def getJobInfo(jobClass : Class[_]): JobInfo = jobClass.getAnnotation(classOf[JobInfo])/*** jobId与jobName映射关系* @return*/def jobIdNameMap : Map[String, String]={jobWithAnnotation.asScala.map{sub =>val jobInfo = getJobInfo(sub)Map(jobInfo.jobId() -> jobInfo.jobName())}.fold(Map())((i,j) => i++j)}/*** JobObject与JobEnum映射关系* @return*/def jobClassInfoMap: Map[String, JobInfo] = {jobWithAnnotation.asScala.map{sub =>Map(sub.getName -> getJobInfo(sub))}.fold(Map())((i,j) => i++j)}/*** jobId与JobEnum映射关系* @return*/def jobIdInfoMap: Map[String, JobInfo] = {jobWithAnnotation.asScala.map{sub =>val jobInfo = getJobInfo(sub)Map(jobInfo.jobId() -> jobInfo)}.fold(Map())((i,j) => i++j)}/*** jobId与JobObject映射关系* @return*/def jobIdClassMap: Map[String, Class[_ <: Job]] = {jobWithAnnotation.asScala.map{sub =>Map(getJobInfo(sub).jobId() -> sub.asInstanceOf[Class[_ <: Job]])}.fold(Map[String, Class[_ <: Job]]())((i,j) => i++j)}def main(args: Array[String]): Unit = {println(jobIdClassMap)}
}

至此,我们就可以获取所有被特定注解引用的类信息及注解信息,我们就可以全局管理特定类信息。

实现JobEnum后就可以统一对定时任务管理实现:

1.新添加定时任务完全可以制定一个Job子类,其他操作自动维护进去;

2.每个Job子类里面都需要实现 override def getJobAndApiInfo(context: JobExecutionContext): (String, String, JobEnum) 方法,这个也可以省掉,直接在父类统一实现;

3.统一修改定时任务开关及时间接口;

4.统一对定时任务启动时重启,就可以统一重启,不需要单独添加代码启动;

1上面代码片段“将某些类添加注解”

2父类代码如下:

import java.io.{PrintWriter, StringWriter}import com.github.dapeng.core.helper.MasterHelper
import com.today.api.financetask.scala.enums.TScheduledTaskLogEnum
import com.today.service.financetask.action.sql.ScheduledTaskLogSql
import com.today.service.financetask.util.{AppContextHolder, Debug}
import com.today.service.financetask.utils.JobInfo
import org.quartz.{Job, JobExecutionContext}
import org.slf4j.LoggerFactory
import org.springframework.transaction.TransactionStatus
import org.springframework.transaction.support.TransactionTemplateimport scala.util.{Failure, Success, Try}/*** the abstract class for job*/
trait AbstractJob extends Job{/** 日志 */val logger = LoggerFactory.getLogger(getClass)/*** execute the job* @param context*/override def execute(context: JobExecutionContext): Unit = {getJobAndApiInfo(context) match {case Some(x) => execute(context, x.jobId, x.jobName)case None => logger.error("没有定义JobEnum及对应JobObject,请检查")}}/*** execute the job* @param context* @param jobId* @param jobName*/def execute(context: JobExecutionContext, jobId : String, jobName: String): Unit = {//判断是否是选中的master节点,不是master节点不执行定时任务if (!MasterHelper.isMaster("com.today.api.financetask.service.FinanceScheduledService", "1.0.0")) {logger.info(s"Can't select master to run the job ${jobId}: ${jobName}")return}//记录开始日志val logId = ScheduledTaskLogSql.insertScheduledTaskLog(jobId)context.put("logId", logId)logger.info(s"Starting the job ${jobId}: ${jobName} ...")//事物处理val transactionTemplate: TransactionTemplate = AppContextHolder.getBean("transactionTemplate")transactionTemplate.execute((status: TransactionStatus) =>{Debug.reset()//执行任务Try(Debug.trace(s"${jobId}:${jobName}")(run(context))) match{case Success(x) => {logger.info(s"Successfully execute the job ${jobId}: ${jobName}")successLog(logId)}case Failure(e) => {logger.error(s"Failure execute the job ${jobId}: ${jobName}", e)failureLog(logId, status, e)}}Debug.info()})}/*** get the api information* @return (interface name, interface version, JobEnum)*/def getJobAndApiInfo(context: JobExecutionContext) : Option[JobInfo] ={JobEnum.jobClassInfoMap.get(this.getClass.getName)}/*** start up the scheduled task* @param context JobExecutionContext*/def run(context: JobExecutionContext)/*** 成功日志记录* @param logId*/def successLog(logId: Long): Unit ={ScheduledTaskLogSql.updateExportReportRecord(logId, TScheduledTaskLogEnum.SUCCESS, "Success")}/*** 失败日志记录* @param logId*/def failureLog(logId: Long, status: TransactionStatus, e: Throwable): Unit ={status.setRollbackOnly()ScheduledTaskLogSql.updateExportReportRecord(logId, TScheduledTaskLogEnum.FAILURE, getExceptionStack(e))}/**** 功能说明:在日志文件中 ,打印异常堆栈* @param e : Throwable* @return : String*/def getExceptionStack(e: Throwable): String = {val errorsWriter = new StringWritere.printStackTrace(new PrintWriter(errorsWriter))errorsWriter.toString}
}

3 统一修改定时任务开关及时间代码如下:

import com.today.api.financetask.scala.enums.{TScheduledTaskHasDeletedEnum, TScheduledTaskIsStartEnum}
import com.today.api.financetask.scala.request.StartOrStopByNameRequest
import com.today.api.financetask.scala.response.ServiceResponse
import com.today.service.commons.Action
import com.today.service.commons.Assert.assert
import com.today.service.commons.exception.CommonException.illegalArgumentException
import com.today.service.financetask.action.sql.ScheduledTaskActionSql
import com.today.service.financetask.dto.TScheduledTask
import com.today.service.financetask.job.define.JobEnum
import com.today.service.financetask.query.sql.ScheduledTaskQuerySql
import com.today.service.financetask.util.{CronConverter, QuartzManager}/*** @description: 启停定时任务* @author zhangc* @date 2018\8\1 0001 15:02* @version 1.0.0*/
class StartOrStopByNameAction (request: StartOrStopByNameRequest)  extends Action[ServiceResponse] {override def preCheck: Unit = {assert(!TScheduledTaskIsStartEnum.isUndefined(request.flag.id), illegalArgumentException("错误的启停标志!"))}/*** 根据传入的定时任务名称和启停标志,来判断启动或者停止定时任务* 如果是1则更新数据库,删除定时任务,重新添加定时任务* 如果是0则更新数据库,删除定时任务* @return*/override def action: ServiceResponse = {val scheduledTask = ScheduledTaskQuerySql.queryByJobId(request.processName)val cron = CronConverter.convertHourMinuteToCron(request.processTime)val jobInfo = JobEnum.jobIdInfoMap(request.processName)//修改定时任务时间, 保存入库if(scheduledTask.isEmpty){ScheduledTaskActionSql.insertTScheduledTask(TScheduledTask(jobInfo.jobName,request.processName,cron,None,request.flag.id,None,null,null,TScheduledTaskHasDeletedEnum.NO.id))} else {ScheduledTaskActionSql.updateTaskIsStart(request.flag.id,cron, request.processName)}request.flag match {case TScheduledTaskIsStartEnum.YES =>  QuartzManager.modifyJobTime(request.processName, cron, JobEnum.jobIdClassMap(jobInfo.jobId()))case _ =>  QuartzManager.removeJob(request.processName)}ServiceResponse("200","success")}
}

4下面就是统一对定时任务启动时重启,就可以统一重启,不需要单独添加代码启动:

import com.today.api.financetask.scala.enums.TScheduledTaskIsStartEnum
import com.today.api.financetask.scala.request.QueryAutoConfigRequest
import com.today.service.financetask.job._
import com.today.service.financetask.job.define.JobEnum
import com.today.service.financetask.query.sql.{AutoConfigQuerySql, ScheduledTaskQuerySql}
import com.today.service.financetask.util.QuartzManager
import com.today.service.financetask.utils.JobInfo
import org.slf4j.LoggerFactory
import org.springframework.context.ApplicationListener
import org.springframework.context.event.ContextRefreshedEvent
import org.springframework.stereotype.Service/***  类功能描述: 定时器监听器, 服务启动时启动定时器** @author BarryWang create at 2018/5/11 12:04* @version 0.0.1*/
@Service
class ScheduleStartListener extends ApplicationListener[ContextRefreshedEvent] {/** 日志 */val logger = LoggerFactory.getLogger(getClass)/*** 启动加载执行定时任务*/override def onApplicationEvent(event: ContextRefreshedEvent): Unit = {logger.info("=======服务器重启定时任务启动start=======")//启动服务时恢复常规定时任务
    JobEnum.values.foreach(recoveryCommonJob(_))logger.info("=======服务器重启定时任务启动end=======")}/*** 恢复通用定时任务* @param jobInfo 定时任务枚举*/private def recoveryCommonJob(jobInfo: JobInfo)={try {val jobClass = JobEnum.jobIdClassMap(jobInfo.jobId)ScheduledTaskQuerySql.queryByJobId(jobInfo.jobId) match {case Some(x) => {x.isStart match {case TScheduledTaskIsStartEnum.YES.id => {QuartzManager.addJobByCron(jobInfo.jobId, x.jobCron, jobClass)logger.info(s"定时任务:'${jobInfo.jobName}'启动成功!")}case _ => logger.info(s"定时任务:'${jobInfo.jobName}'is_start标志为0,不启动")}}case None => QuartzManager.addJobByCron(jobInfo.jobId, jobInfo.defaultCron(), jobClass)}} catch {case e : Exception => logger.error(s"定时任务:'${jobInfo.jobName}'启动失败, 失败原因:", e)}}
}

本部分也是对Quartz实现可配置的分布式定时任务的优化重构,可详见:

Quartz实现分布式可动态配置的定时任务

转载于:https://www.cnblogs.com/barrywxx/p/10810055.html

Java Scala获取所有注解的类信息相关推荐

  1. java后台获取和js拼接展示信息

    java后台获取和js拼接展示信息: html页面代码: <div class="results-bd"><table id="activityInfo ...

  2. java scala 获取类_在Scala 2.10中获取java.lang.Class [T]的Scala类型

    您可以像这样实现您的方法: def getType[T](clazz: Class[T])(implicit runtimeMirror: ru.Mirror) = runtimeMirror.cla ...

  3. 微信小程序在java后台获取用户unionid等敏感信息

    最近在弄小程序,阅读了微信官方文档,上面说可以在后台获取用户的openid和unionid这些敏感信息,当然网上也有不少帖子,有的是在前台获取的,不过这里不太建议把这些敏感信息放在前台,毕竟不太安全. ...

  4. java 反射 获取 实例_java通过类反射获取某个类的所有信息--代码实例

    package huang.de.wei; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; ...

  5. java实现获取各网站的机票信息_java爬取某个机票查询网站上面的信息(刚学!!!)...

    [Java] 纯文本查看 复制代码[ 本帖最后由 shangjS009 于 2018-5-25 15:41 编辑 ]\n\n@RequestMapping(value = "${adminP ...

  6. java反射获取所有接口实现类

    需求描述 项目业务前后端交互需要的一些特定值需要用枚举类型列举出来,并且每个枚举值对应的外部使用值不是固定的, 类似于 APPLE("apple","苹果") ...

  7. Java用数组的包文件_在Java中获取包内的类文件数组

    我能够使用普通的文件I / O和搜索机制来解决这个问题.您可以在此处查看答案. private static List getClassesForPackage(Package pkg) { Stri ...

  8. java 注释 过时_Java 注解

    前言 为什么需要学习注解? 1.能够灵活地使用框架提供的注解,最后能够读懂框架的源码 2.能够配合反射将代码书写更加的灵活,更加易于维护易于扩展,Properties配置,XML配置,注解配置[Jav ...

  9. Java 使用反射处理注解

    Java 使用反射处理注解 自定义注解的格式: [public|final] @interface 注解名//@interface 表明:这是一个自定义注解 {注解元素//注解元素 是无参数的方法 } ...

最新文章

  1. CentOS 7系统关闭yum自动下载更新
  2. 飞书上点链接怎么指定跳转浏览器_链接示例表功能还可以这样用??
  3. 实时获取ccd图像_四元数数控:CCD视觉检测定位系统在玻璃瓶缺陷的检测
  4. mysql创建只读权限用户_新品速递 | Harbor 修复权限提升漏洞,MySQL Plus 支持密码强度校验以及审计功能...
  5. BITMAPINFO结构
  6. linux下重启mysql php nginx
  7. mysql 事务处理null_如何使用Mysql正确的处理财务数据
  8. 2022-2028年中国差旅管理行业市场行情动态及投资潜力研究报告
  9. 华丽的Flutter的demo----新闻阅读+音乐+短视频+小说
  10. U8采购订单联查采购入库单
  11. 拼多多搜索热度怎么做|重庆乾胤
  12. [转] 从1个月到2岁半的育儿方案,有了它宝宝都不用去上早教啦
  13. LoRa和NB-IoT会长期共存吗?
  14. ubuntu中显示实时网速的方法
  15. CSP 201809 第二题 买菜
  16. 白盒/黑盒/灰盒测试的区别
  17. cocos3D 初体验
  18. AndroidPlayPlane战机小游戏
  19. COLA 4.0 - DDD项目实践
  20. Handler原理剖析

热门文章

  1. 计算机考试c++语言程序设计,2017年全国二级计算机C++语言程序设计考试大纲
  2. 金融数据分析与挖掘实战1.4.1-1.4.3
  3. 前端开发书籍推荐与学习路线
  4. 畅易阁老是显示服务器忙,畅易阁全服开放 盘点天龙玩家卖号的几大原因
  5. 电脑怎么彻底删除软件_电脑强力卸载工具,删除电脑无用软件,让电脑更加快捷顺畅...
  6. python常用包有哪些品牌_python 常用包总结
  7. linux socket 结构定义 send,Linux下Socket编程中用send发送结构体
  8. wow修改人物模型_抖音爆款心法:一个模型+五组案例
  9. redis循环键_Redis 性能优化的 13 条军规!史上最全
  10. STM8单片机 PWM无波形输出解决方法