SpringAOP&&定时任务简单实现接口访问入表和定时任务接口重试
Posted heiqiubaihu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringAOP&&定时任务简单实现接口访问入表和定时任务接口重试相关的知识,希望对你有一定的参考价值。
# SpringAOP&&定时任务简单实现接口访问入表和定时任务接口重试 #
Spring aop
Spring 定时任务
代理模式深化
1.表设计
2.Aop主要代码
@Aspect
@Component
public class AopUtils implements Ordered {
//当前
private static final Logger logger = LoggerFactory.getLogger(AopUtils.class);
public static String AOPLOG_NO_RETREN_VALUE = "NONE RETURN";
@Value("${接口地址.url}")
private String url;
@Autowired
private RequestInfoDao requestInfoDao;
/**
* API 接口日志访问记录
* 环绕通知实现
* @param jp
* @return
*/
@Around("execution(* com.*.*.modules.*.service.CommonService.*(..))")
public Object logApiMethod(ProceedingJoinPoint jp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
Object rvt = null;
RequestInfo requestInfo = new RequestInfo();
//配合后面的定时任务重试接口机制
if(sra == null) {
try {
rvt = jp.proceed(jp.getArgs());
String params = "";
List<Object> filterArgs = Lists.newArrayList();
try {
if(jp.getArgs()!=null) {
Arrays.stream(jp.getArgs()).forEach(arg -> {
if (!(arg instanceof HttpServletRequest || arg instanceof HttpServletResponse)) {
filterArgs.add(arg);
}
});
}
params = (filterArgs.size()==0)? "":JsonMapper.toJsonString(filterArgs);
}catch (Exception e) {
params = filterArgs+"";
}
String returnValue = "";
try {
returnValue = rvt==null ? "": JsonMapper.toJsonString(rvt);
}catch (Exception e) {
returnValue = "返回值过长不显示";
}
requestInfo.setParam(params);
requestInfo.setReturnValue(returnValue);
requestInfo.setUpdateDate(new Date());
User user = new User("接口重试");
requestInfo.setUpdateBy(user);
requestInfo.setResult(true);
requestInfo.setErrorResson(null);
requestInfoDao.updateByParams(info);
return rvt;
} catch (Throwable var6) {
requestInfo.setResult(false);
requestInfo.setErrorResson("线上接口访问异常:"+var6.getMessage());
logger.error("线上接口访问异常:", var6);
}
}
HttpServletRequest request = sra.getRequest();
requestInfo.setResult(true);
try {
rvt = jp.proceed(jp.getArgs());
} catch (Throwable var6) {
requestInfo.setResult(false);
requestInfo.setErrorResson("线上接口访问异常:"+var6.getMessage());
logger.error("线上接口访问异常:", var6);
}
String methodName = jp.getSignature().getName();
//参数写成一个集合数组,接口重试的时候需要转换
String params = "";
List<Object> filterArgs = Lists.newArrayList();
try {
if(jp.getArgs()!=null) {
Arrays.stream(jp.getArgs()).forEach(arg -> {
if (!(arg instanceof HttpServletRequest || arg instanceof HttpServletResponse)) {
filterArgs.add(arg);
}
});
}
params = (filterArgs.size()==0)? "":JsonMapper.toJsonString(filterArgs);
}catch (Exception e) {
params = filterArgs+"";
}
String returnValue = "";
if(isShowReturnValue(methodName)) {
try {
returnValue = rvt==null ? "": JsonMapper.toJsonString(rvt);
}catch (Exception e) {
returnValue = "返回值过长不显示";
}
}else {
returnValue = "不显示返回值";
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String requestURI = httpServletRequest.getRequestURI();
String beanName = jp.getThis().getClass().getSimpleName();
int num = beanName.indexOf("$$");
beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring( 1, num);
requestInfo.setId(IdGen.uuid());
requestInfo.setBeanName(beanName);
requestInfo.setMethod(methodName);
requestInfo.setParam(params);
requestInfo.setRequestUrl(url+requestURI);
requestInfo.setReturnValue(returnValue);
requestInfo.setCreateDate(new Date());
requestInfo.setUpdateDate(new Date());
//接口是否可重复
Method aopMethod = ((MethodSignature)jp.getSignature()).getMethod();
Method m = jp.getTarget().getClass().getDeclaredMethod(methodName, aopMethod.getParameterTypes());
InterfaceRepeatFlag interfaceRepeatFlag = m.getAnnotation(InterfaceRepeatFlag.class);
if (interfaceRepeatFlag == null){
requestInfo.setRepeatFlag(false);
}else {
requestInfo.setRepeatFlag(interfaceRepeatFlag.value());
}
User user = new User();
user.setId("接口调用");
requestInfo.setCreateBy(user);
requestInfo.setUpdateBy(user);
if(requestInfoDao != null) {
requestInfoDao.insert(requestInfo);
}
return rvt;
}
private boolean isShowReturnValue(String methodName) {
List<String> debugRoles = Arrays.asList(AOPLOG_NO_RETREN_VALUE.split(","));
for(String debugRole : debugRoles) {
if(!StringUtils.isBlank(methodName)
&& methodName.indexOf(debugRole) == 0){
return false;
}
}
return true;
}
@Override
public int getOrder() {
return 1001;
}
}
3.定时任务配置
<bean name="schedulerFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 定义数据源 ,数据源里面需要Quzrtz集群所需要的表 -->
<property name="dataSource">
<ref bean="dataSource" />
</property>
<!-- 指定spring容器的key,如果不设定在job中的jobmap中是获取不到spring容器的 -->
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<!-- 指定spring的配置相关信息 -->
<property name="configLocation" value="classpath:quartz.properties" />
<!-- 指定触发器,可以指定多个 -->
<property name="triggers">
<list>
<ref bean="interfaceJobTrigger"/>
</list>
</property>
</bean>
<!-- 定义任务 -->
<bean id="interfaceJob" class="com.*.*.modules.quzrtz.service.interfaceJob"/>
<bean id="interfaceJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<!-- 上面的任务的代理类(自己实现) -->
<value>com.*.*.modules.quzrtz.scheduler.InterfaceJobSchedule</value>
</property>
<property name="description">
<value>定时任务接口重试</value>
</property>
<property name="jobDataAsMap">
<map>
<!--实际的任务BeanName,填上EventMonitorService的BeanName -->
<entry key="targetObject" value="interfaceJob" />
<!-- 执行Bean中的哪个方法 -->
<entry key="targetMethod" value="repeatInterface" />
</map>
</property>
</bean>
<bean id="interfaceJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<!-- 任务代理Bean name -->
<ref bean="interfaceJobDetail" />
</property>
<property name="description">
<!-- 任务代理Bean name -->
<value>定时任务接口重试</value>
</property>
<property name="cronExpression">
<!-- 配置表达式,这里表示每1分钟执行一次 -->
<value>0 0/1 * * * ?</value>
</property>
</bean>
4.定时任务
@Transactional(readOnly = false)
public void repeatInterface() {
RequestInfo requestInfo = new RequestInfo();
requestInfo.setRepeatFlag(true);
requestInfo.setResult(false);
List<RequestInfo> requestInfoList = requestInfoDao.findAllList(requestInfo);
for (RequestInfo requestInfo : requestInfoList){
String paramStr = requestInfo.getParam();
String beanStr = requestInfo.getBeanName();
String methodStr = requestInfo.getMethod();
try {
Object obj = SpringContextHolder.getBean(beanStr);
Method m = null;
Method[] methods = obj.getClass().getMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {
if (method.getName().equals(methodStr)) {
m = method;
break;
}
}
}
Class paramCls = m.getParameterTypes()[0];
List<Object> params = JSONArray.parseArray(paramStr);
MethodUtils.invokeExactMethod(obj, methodStr, JSON.parseObject(JSONObject.toJSONString(params.get(0)), paramCls));
}catch (Exception e){
e.printStackTrace();
logger.error("接口重试:失败,失败原因:"+e.getMessage());
continue;
}
logger.info("接口重试成功:类名"+beanStr+";方法:"+methodStr+";参数:"+paramStr+";结束重试");
}
}
5.定时任务调度器-定时任务代理
public class InterfaceJobSchedule extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(InterfaceJobSchedule.class);
private String targetObject;
private String targetMethod;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
Object otargetObject = SpringContextHolder.getBean(targetObject);
Method m = null;
Method[] methods = otargetObject.getClass().getMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {
if (method.getName().equals(targetMethod)) {
m = method;
break;
}
}
m.invoke(otargetObject, new Object[]{});
}
} catch (Exception e) {
logger.error("InterfaceJobSchedule Exception:", e);
}
}
/**
* @param targetObject the targetObject to set
*/
public void setTargetObject(String targetObject) {
this.targetObject = targetObject;
}
/**
* @param targetMethod the targetMethod to set
*/
public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
}
6.接口重试注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterfaceRepeatFlag {
public boolean value() default true;
}
7.学习总结
Spring AOP核心是代理模式,可见代理模式的拓展性有多强,有业务的代码才会有收获,试一试,收获颇多
以上是关于SpringAOP&&定时任务简单实现接口访问入表和定时任务接口重试的主要内容,如果未能解决你的问题,请参考以下文章
Kubernetes中的Job(工作计划)&amp;CronJob(定时工作计划)Demo+实战