Java Scala获取所有注解的类信息
要想获取使用指定注解的类信息,可借助工具:
org.reflections.Reflections
此工具将Java反射进行了高级封装,Reflections 通过扫描 classpath,索引元数据,允许在运行时查询这些元数据,也可以保存收集项目中多个模块的元数据信息。
使用 Reflections 可以查询以下元数据信息:
)获得某个类型的所有子类型
)获得标记了某个注解的所有类型/成员变量,支持注解参数匹配。
)使用正则表达式获得所有匹配的资源文件
)获得所有特定签名(包括参数,参数注解,返回值)的方法
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.Calendar import 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.getInstance
cal.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.util import com.today.service.financetask.utils.JobInfo
import org.quartz.Job
import org.reflections.Reflections import 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.TransactionTemplate import 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 StringWriter
e.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实现分布式可动态配置的定时任务
Java Scala获取所有注解的类信息的更多相关文章
- java后台获取和js拼接展示信息
java后台获取和js拼接展示信息: html页面代码: <div class="results-bd"> <table id="activityInf ...
- java反射获取和设置实体类的属性值 递归所有父类
最近做一个通用数据操作接口,需要动态获取和设置实体类的属性值,为了通用实体做了多重继承,开始网上找到代码都不支持父类操作,只能自己搞一个工具类了,此工具类可以设置和获取所有父类属性,代码贴下面拿走不谢 ...
- Java——反射:运行时的类信息
RTTI的使用 如果不知道某个对象的确切类型,RTTI会告诉我们,但是有一个限制:这个类型在编译时必须已知,这样才能使用RTTI识别它,并利用这些信息做一些有用的事情. 2.什么情况下需要反射 假设 ...
- Java:不得不知的Object类
目录 一.equals 1.equals与==有啥区别? 2.equals方法的规范 3.instanceof 和getClass() 4.其他总结 二.hashCode 1.hashCode的规范 ...
- MFC中关于运行时类信息及动态创建对象的两个宏的意义(转)
http://blog.csdn.net/ligand/article/details/49839507 MFC运行时类信息 用途: 程序在运行时,获取对象类的信息及类的继承关系 实现: 1.定义的类 ...
- Java反射获取类和对象信息全解析
反射可以解决在编译时无法预知对象和类是属于那个类的,要根据程序运行时的信息才能知道该对象和类的信息的问题. 在两个人协作开发时,你只要知道对方的类名就可以进行初步的开发了. 获取类对象 Class.f ...
- JAVA基础知识之JVM-——通过反射查看类信息
Class实例 当类被加载之后,JVM中就会生成一个Class实例,通过这个实例就可以访问JVM中的这个类.有三种方式可以获取Class对象 使用Class的静态方法forName(完整包名) 调用类 ...
- java 编程基础:注解(Annotation Processing Tool)注解处理器 利用注解解读类属性生成XML文件
APT的介绍: APT(Annotation Processing Tool)是一种注解处理工具,它对源代码文件进行检测,并找出源文件所包含的注解信息,然后针对注解信息进行额外的处理. 使用APT工具 ...
- java 利用ManagementFactory获取jvm,os的一些信息--转
原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...
随机推荐
- Kubernetes 企业级集群部署方式
一.Kubernetes介绍与特性 1.1.kubernetes是什么 官方网站:http://www.kubernetes.io • Kubernetes是Google在2014年开源的一个容器集群 ...
- SQL学习笔记之 数据库基础(一)
数据库基础 数据库系统的组成:由数据库,数据库管理软件,数据库管理员DBA,支持数据库系统的硬件和软件组成,其中数据库管理员是对数据库进行规划.设计.维护.和监视的专业管理人员,在数据库系统中起着非常 ...
- 深入理解TCP/IP应用层
TCP/IP四层模型分为: 应用层,传输层(只关注起点(发送者)和终点(接收者)),网络层(规划出一条或几条路线),数据链路层(关注两个相邻点之间怎么传输) 协议 应用层 DNS,URI,HT ...
- [基础] - 从xx语言是跨平台的说起
我经常碰到一些人在说xx语言跨平台而yy语言不是(为避免不必要的纷争,在此不写具体语言但不影响阅读),从而来表明自己使用xx语言进行程序开发进而在编程语言鄙视链上高高在上很有优越感. 大概是从Java ...
- MySql数据库中正则表达式
命令 说明 ^ 在字符的开启处进行匹配 $ 在字符的末尾处进行匹配 . 匹配任何字符(包括回车和新行) [-.] 匹配括号内的任意单个字符 [m-n] 匹配m到n之间的任意单个字符,例如[0-9],[ ...
- Lambda(二)lambda表达式使用
Lambda(二)lambda表达式使用 Lambda 表达式组成: /* param list arrow lambda body (o1,o2) -> o1.getColor().Compa ...
- 深入浅出JVM的锁优化案例
锁优化 适应性自旋(Adaptive Spinning) 线程阻塞的时候,让等待的线程不放弃cpu执行时间,而是执行一个自旋(一般是空循环),这叫做自旋锁. 自旋等待本身虽然避免了线程切换的开销,但它 ...
- Linux文件共享服务 FTP,NFS 和 Samba
Linux 系统中,存储设主要有下面几种: DAS DAS 指 Direct Attached Storage,即直连附加存储,这种设备直接连接到计算机主板总线上,计算机将其识别为一个块设备,例如常见 ...
- Android 自定义水平进度条的圆角进度
有时项目中需要实现水平圆角进度,如下两种,其实很简单 下面开始看代码,先从主界面布局开始看起: <?xml version="1.0" encoding=" ...
- springcloud学习之路: (二) springcloud打jar包并批量运行
springcloud中内置了tomcat所以打包的时候是直接把tomcat打入jar包 之后就可以做到, 单独的服务, 独立的jar包, 独立运行的效果了. 一.打jar包 1. 在pom.xml文 ...