问题:
自定义注解,作为切点,切面失效。一开始使用环绕通知,切面优先级为@Order(value = Integer.MIN_VALUE),注解标注的方法中,部分方法的切面失效。
可能的原因:
方法调用非代理对象代用的,只有代理对象调用才可以走切面;
方法非public方法,非public方法注解失效;
多个注解切面冲突导致无效
最后解决:
切面优先级由@Order(value = Integer.MIN_VALUE) 改为 1
环绕通知 @Around 改为 前置通知 @Before,ProceedingJoinPoint 改为 JoinPoint
真正原因:未知
代码如下:
自定义注解
package cn.damai.mz.pms.common.bcp.annotation;
import cn.damai.mz.enums.common.OperateCrudEnum;
import cn.damai.mz.pms.common.enums.OperateSceneEnum;
import com.sun.tools.internal.xjc.model.CDefaultValue;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* BCP操作注解,注解+切面 监控操作
* @author xlp
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BcpMonitor {
/**
* @Transactional
* 操作类型 {@link cn.damai.mz.pms.common.enums.OperateSceneEnum}
*/
OperateSceneEnum operateSceneEnum();
/**
* @Transactional
* CRUD类型 {@link cn.damai.mz.enums.common.OperateCrudEnum}
*/
OperateCrudEnum operateCrudEnum();
/**
* 存放不规则的字段名称,如projectID,eventID。。。
* @return
*/
String projectIdFieldName() default "";
String eventIdFieldName() default "";
}
切面
package cn.damai.mz.pms.server.bcp.aspect;
import cn.damai.mz.enums.common.OperateCrudEnum;
import cn.damai.mz.exception.MzException;
import cn.damai.mz.pms.common.bcp.annotation.BcpMonitor;
import cn.damai.mz.pms.common.enums.OperateSceneEnum;
import cn.damai.mz.pms.common.enums.PmsErrorEnum;
import cn.damai.mz.pms.common.enums.PmsSequenceIdKeyEnum;
import cn.damai.mz.pms.common.sequence.service.SequenceIdService;
import cn.damai.mz.pms.domain.param.EventChannelExtParamDTO;
import cn.damai.mz.pms.server.bcp.dto.PmsOperateBcpLogParameter;
import cn.damai.mz.pms.server.bcp.service.PmsOperateBcpLogService;
import cn.damai.mz.pms.server.param.BizEventChannelParamDTO;
import cn.damai.mz.pms.server.param.BizEventChannelSettingImportParamDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taobao.csp.switchcenter.annotation.AppSwitch;
import com.taobao.csp.switchcenter.bean.Switch;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* BCP操作通用切面,注解+切面 监控操作
* 只适用,入参只有一个,且为对象,包含projectId,eventId,eventName其中一个
*/
@Component
@Order(1)
@Aspect
public class BcpMonitorAspect {
private static final Logger log = LoggerFactory.getLogger(BcpMonitorAspect.class);
@Autowired
PmsOperateBcpLogService pmsOperateBcpLogService;
@Autowired
SequenceIdService sequenceIdService;
@AppSwitch(level = Switch.Level.p3, des = "pms是否开启BCP监听日志写入DB")
public static Boolean bcpAspect = true;
/**
* 批量删除场次渠道授权
*/
static final String DELETEEVENTCHANNEL = "deleteEventChannel";
/**
* 修改场次渠道授权
*/
static final String UPDATEEVENTCHANNELCONTROL = "updateEventChannelControl";
/**
* 变更渠道授权范围
*/
static final String CHANGEEVENTSALECONTROL = "changeEventSaleControl";
/**
* 批量场次渠道设置,票品授权
*/
static final String MXIMPORTEVENTCHANNELSETTINGSYNC = "mxImportEventChannelSettingSync";
// @Pointcut(value = "execution(* cn.damai.mz.pms.biz.eventchannel.service.impl.BizMzEventChannelServiceImpl.deleteEventChannel(..))")
// public void deleteEventChannelPointcut() {
// }
@Before("@annotation(cn.damai.mz.pms.common.bcp.annotation.BcpMonitor)")
public void saveOperateBcpLog(JoinPoint point) throws Throwable {
// Object result = point.proceed();
try {
if (bcpAspect) {
// return result;
log.info("BcpMonitorAspect#saveOperateBcpLog--start:");
//获取入参
Object[] args = point.getArgs();
//获取注解信息
Signature signature = point.getSignature();
//方法信息
Method method = checkParam(args, signature);
//方法入参map
Map<String, Object> map = getParamMap(args, method);
//封装入参
BcpMonitor annotation = method.getAnnotation(BcpMonitor.class);
PmsOperateBcpLogParameter bcpLogParameter = getBcpLogParameter(map, annotation);
//入库
log.info("pmsOperateBcpLogService#create:{}", JSONObject.toJSONString(bcpLogParameter));
pmsOperateBcpLogService.create(bcpLogParameter);
log.info("BcpMonitorAspect#saveOperateBcpLog--end!");
}
} catch (Exception e) {
log.warn("BcpMonitorAspect#saveOperateBcpLog 失败:", e);
}
// Object result = point.proceed();Proceeding
// return result;
}
/**
* 根据不同的方法 获取不同的参数,新场景维护此方法即可
*
* @param args
* @param method
* @return
*/
private Map<String, Object> getParamMap(Object[] args, Method method) {
Map<String, Object> map = new HashMap<>(16);
String name = method.getName();
log.info("BcpMonitorAspect#getParamMap,methodName:{}", name);
switch (name) {
case DELETEEVENTCHANNEL:
for (Object object : args) {
if (object instanceof List) {
JSONArray eventSaleControlIds = JSONObject.parseArray(JSONObject.toJSONString(object));
//场次渠道授权ID eventSaleControlIds
map.put("eventSaleControlIds", eventSaleControlIds);
break;
}
}
break;
case UPDATEEVENTCHANNELCONTROL:
for (Object object : args) {
if (object instanceof BizEventChannelParamDTO) {
// BizEventChannelParamDTO paramDTO = (BizEventChannelParamDTO) object;
// map.put("eventId", paramDTO.getEventId());
map = JSONObject.parseObject(JSONObject.toJSONString(object), Map.class);
break;
}
}
break;
case CHANGEEVENTSALECONTROL:
for (Object object : args) {
if (object instanceof EventChannelExtParamDTO) {
map = JSONObject.parseObject(JSONObject.toJSONString(object), Map.class);
break;
}
}
break;
case MXIMPORTEVENTCHANNELSETTINGSYNC:
for (Object object : args) {
if (object instanceof BizEventChannelSettingImportParamDTO) {
map = JSONObject.parseObject(JSONObject.toJSONString(object), Map.class);
break;
}
}
break;
default:
map = JSONObject.parseObject(JSONObject.toJSONString(args[0]), Map.class);
break;
}
return map;
}
private PmsOperateBcpLogParameter getBcpLogParameter(Map<String, Object> map, BcpMonitor annotation) {
//组装操作记录
PmsOperateBcpLogParameter param = new PmsOperateBcpLogParameter();
param.setId(sequenceIdService.sequenceId(PmsSequenceIdKeyEnum.PMS_OPERATE_BCP_LOG_ID));
param.setCreateUserId(map.get("operatorId") != null ? Long.valueOf(map.get("operatorId").toString()) : null);
param.setModifyUserId(map.get("operatorId") != null ? Long.valueOf(map.get("operatorId").toString()) : null);
param.setProjectId(map.get("projectId") != null ? Long.valueOf(map.get("projectId").toString())
: StringUtils.isNotEmpty(annotation.projectIdFieldName()) ? Long.valueOf(map.get(annotation.projectIdFieldName()).toString()) : null);
param.setEventId(map.get("eventId") != null ? Long.valueOf(map.get("eventId").toString())
: StringUtils.isNotEmpty(annotation.eventIdFieldName()) ? Long.valueOf(map.get(annotation.eventIdFieldName()).toString()) : null);
//获取注解 获取操作类型
OperateSceneEnum operateSceneEnum = annotation.operateSceneEnum();
OperateCrudEnum operateCrudEnum = annotation.operateCrudEnum();
if (null == operateSceneEnum || null == operateCrudEnum) {
log.error("BcpMonitorAspect#saveOperateBcpLog,BcpMonitor注解参数存在空值!");
throw new MzException(PmsErrorEnum.PARAM_VALID_ERROR);
}
param.setOperateScene(operateSceneEnum.value());
param.setOperateCrud(operateCrudEnum.getCode());
//扩展内容
Map<String, Object> extraAttr = new HashMap();
if (OperateCrudEnum.CREATE.equals(operateCrudEnum)) {
if (OperateSceneEnum.PROJECT.equals(operateSceneEnum)) {
extraAttr.put("projectName", map.get("projectName"));
}
if (OperateSceneEnum.EVENT.equals(operateSceneEnum)) {
extraAttr.put("eventName", map.get("eventName"));
}
}
extraAttr.put("ptnrId", map.get("ptnrId"));
extraAttr.put("tenantId", map.get("tenantId"));
extraAttr.put("userId", map.get("userId"));
extraAttr.put("eventSaleControlIds", map.get("eventSaleControlIds"));
extraAttr.put("targetProjectId", map.get("targetProjectId"));
extraAttr.put("targetEventIds", map.get("targetEventIds"));
param.setExtraAttr(JSON.toJSONString(extraAttr));
return param;
}
private Method checkParam(Object[] args, Signature signature) {
if (args == null && args.length <= 0) {
log.warn("BcpMonitorAspect#saveOperateBcpLog,BcpMonitor标注方法入参为空");
throw new MzException(PmsErrorEnum.BCP_PARAM_VALID_ERROR);
}
if (signature == null) {
log.warn("BcpMonitorAspect#saveOperateBcpLog,获取签名失败!");
throw new MzException(PmsErrorEnum.BCP_ANALYTIC_ERROR);
}
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method == null) {
log.warn("BcpMonitorAspect#saveOperateBcpLog,获取方法失败!");
throw new MzException(PmsErrorEnum.BCP_ANALYTIC_ERROR);
}
return method;
}
}