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

1 篇文章 0 订阅
问题:

自定义注解,作为切点,切面失效。一开始使用环绕通知,切面优先级为@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;
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java自定义注解和AOP切面是两个不同的概念,但它们可以结合使用来实现一些非常有用的功能。 Java自定义注解是Java语言中的一种特殊的语法结构,它允许开发者在代码中添加一些元数据,以便后续处理程序能够基于这些元数据来进行特定的操作。Java自定义注解可以在类、方法、属性等各种代码元素上进行声明,并且可以指定注解的属性,以提供更多的元数据信息。 AOP(面向切面编程)是一种编程思想,它允许开发者在不改变原有代码的情况下,通过添加额外的代码来实现某些横切关注点的功能。AOP切面是一个包含一组通知(Advice)和切点(Pointcut)的类,它可以在程序运行时自动拦截指定的方法或类,并执行相应的通知。 在Java中,我们可以通过将自定义注解和AOP切面结合使用,来实现一些非常有用的功能。例如,我们可以定义一个名为 @Log 的注解,在程序中使用该注解来标记需要记录日志的方法,然后编写一个AOP切面来拦截这些方法,并在方法执行前后记录日志。这样,我们就可以轻松地实现统一的日志记录功能,而不需要在每个方法中都编写日志记录代码。 下面是一个简单的示例代码,演示了如何使用Java自定义注解和AOP切面来实现统一的日志记录功能: ```java // 定义一个名为 @Log 的注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { } // 编写一个AOP切面,拦截带有 @Log 注解的方法,并记录日志 @Aspect @Component public class LogAspect { @Around("@annotation(log)") public Object around(ProceedingJoinPoint joinPoint, Log log) throws Throwable { String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 开始执行..."); Object result = joinPoint.proceed(); System.out.println("方法 " + methodName + " 执行完成,返回值为:" + result); return result; } } // 在程序中使用 @Log 注解标记需要记录日志的方法 @Service public class UserService { @Log public String getUserInfo(String userId) { // ... } } ``` 在上面的代码中,我们首先定义了一个名为 @Log 的注解,并指定了它的作用范围为方法。然后,我们编写了一个AOP切面 LogAspect,使用 @Around 注解来指定切点为所有带有 @Log 注解的方法。在切面的 around 方法中,我们通过 ProceedingJoinPoint 对象获取当前执行的方法名,并在方法执行前后打印日志。最后,我们在 UserService 类的 getUserInfo 方法上使用了 @Log 注解,表示这个方法需要记录日志。 当程序运行时,LogAspect 切面会自动拦截 UserService 类的 getUserInfo 方法,并执行 around 方法中的逻辑,从而实现了统一的日志记录功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值