自定义注解,作为切点,切面失效。

问题:

自定义注解,作为切点,切面失效。一开始使用环绕通知,切面优先级为@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;
    }
}

版权声明:本文为XiXavier原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。