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的情况,可以使用一些监控工具,比如 ...
随机推荐
- MySQL5.7安装脚本
目录结构: install_mysql.sh:安装脚本 my.cnf: MySQL配置文件 mysql--linux-glibc2.-x86_64.tar.gz:MySQL二进制包 以下为目录中的文件 ...
- csp 201809-1卖菜
问题描述 在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜. 第一天,每个商店都自己定了一个价格.店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商 ...
- npm install 报错 -4048
方法1: 删除npmrc文件. 强调:不是nodejs安装目录npm模块下的那个npmrc文件,而是在C:\Users\{账户}\下的.npmrc文件. 方法2: https://www.jiansh ...
- Ubuntu16.04的搭建l.2.t.p.d(宿舍访问公司内网)
主要的实现步骤 openswan(ipsec) : 提供一个密钥 ppp :提供用户名和密码 xl2tpd : 提供L2TP服务 sysctl : 提供服务器内部转发 iptables : 提供请求从 ...
- python学习3-python views.py的返回值
2.首先要说明一点是,对于HttpRequest对象来说,是Django自己创建的,但是HttpResponse就必须要我们自己创建.注意每个view方法都必须返回一个HttpResponse对象,H ...
- SUSE12-SP2安装教程(虚拟机)
创建虚拟机,安装系统,安装系统后的系统设置 创建虚拟机 将SUSE12-SP2镜像(大于3G)上传到虚拟机主机存储. 创建虚拟机创建虚拟机,CPU>=8核,内存>=16G(注:我这里仅演示 ...
- 通过优化Gunicorn配置获得更好的性能
对于受CPU限制的应用程序,增加了工作程序和/或内核.对于受I / O限制的应用程序,请使用"伪线程". Gunicorn是Python WSGI HTTP Server,通常驻留 ...
- apache配置项
环境:apache2.24 apache 官方文档:http://httpd.apache.org/docs/2.4/ 全部指令索引: http://httpd.apache.org/docs/ ...
- c# 第9节 数据类型之值类型
本节内容: 1:数据类型是什么 1:数据类型是什么 2:数据类型--值类型 3:值类型和引用类型的区分 画图现象: 3:值类型的种类 整数: 浮点数: 字符:
- python函数中的不定长参数
python自定义函数中有两中不定长参数,第一种是*name,第二种是**name.加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数.加了两个星号 ** 的参数会以字典的 ...