Spring @Aspect 切面,动态代理教程

要使用AOP必须知道AOP的原理,这篇文章不做详述, 如需了解, 请直接坐电梯看我的另一片博文, 电梯在此!!!

一般@Aspect 注解的切面, 通常可以用切面表达式, 和注解切面来完成我们的切面编程.

首先必须引入依赖

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.1</version>
        </dependency>

---------------------------------------------------- 直接上代码 -----------------------------------------------------------------------------------------

首先基于注解形式的切面,下面代码,是本人写的RedisLock,分布式锁的

@Aspect
@Component
public class RedisLockAspect {

    private static final Integer MAX_RETRY_COUNT = 3;
    private static final String LOCK_PRE_FIX = "lockPreFix";
    private static final String LOCK_KEY = "lockKey";
    private static final String TIME_OUT = "timeOut"; // second
    private static final int PROTECT_TIME = 2 << 11;//4096

    private static final Logger log = LoggerFactory.getLogger(RedisLockAspect.class);

    @Autowired
    private CommonRedisHelper commonRedisHelper;


    @Pointcut("@annotation(com.shuige.components.cache.annotation.RedisLock)")
    public void redisLockAspect() {
    }

    @Around("redisLockAspect()")
    public void lockAroundAction(ProceedingJoinPoint proceeding) throws Exception {
     
        //获取redis锁
        Boolean flag = this.getLock(proceeding, 0, System.currentTimeMillis());
        if (flag) {
            try {
                proceeding.proceed();
                Thread.sleep(PROTECT_TIME);
            } catch (Throwable throwable) {
                throw new RuntimeException("分布式锁执行发生异常" + throwable.getMessage(), throwable);
            } finally {
                // 删除锁
            }
        } else {
            log.info("其他系统正在执行此项任务");
        }

    }

    /**
     * 获取锁
     *
     * @param proceeding
     * @return
     */
    private boolean getLock(ProceedingJoinPoint proceeding, int count, long currentTime) {
        //获取注解中的参数
        Map<String, Object> annotationArgs = this.getAnnotationArgs(proceeding);
        String lockPrefix = (String) annotationArgs.get(LOCK_PRE_FIX);
        String key = (String) annotationArgs.get(LOCK_KEY);
        long expire = (long) annotationArgs.get(TIME_OUT);
        //String key = this.getFirstArg(proceeding);
        if (StringUtils.isEmpty(lockPrefix) || StringUtils.isEmpty(key)) {
            // 此条执行不到
            throw new RuntimeException("RedisLock,锁前缀,锁名未设置");
        }
        if (commonRedisHelper.setNx(lockPrefix, key, expire)) {
            return true;
        } else {
            // 如果当前时间与锁的时间差, 大于保护时间,则强制删除锁(防止锁死)
            long createTime = commonRedisHelper.getLockValue(lockPrefix, key);
            if ((currentTime - createTime) > (expire * 1000 + PROTECT_TIME)) {
                count ++;
                if (count > MAX_RETRY_COUNT){
                    return false;
                }
                commonRedisHelper.delete(lockPrefix, key);
                getLock(proceeding,count,currentTime);
            }
            return false;
        }
    }

    /**
     * 删除锁
     *
     * @param proceeding
     */
    private void delLock(ProceedingJoinPoint proceeding) {
        Map<String, Object> annotationArgs = this.getAnnotationArgs(proceeding);
        String lockPrefix = (String) annotationArgs.get(LOCK_PRE_FIX);
        String key = (String) annotationArgs.get(LOCK_KEY);
        commonRedisHelper.delete(lockPrefix, key);
    }

    /**
     * 获取锁参数
     *
     * @param proceeding
     * @return
     */
    private Map<String, Object> getAnnotationArgs(ProceedingJoinPoint proceeding) {
        Class target = proceeding.getTarget().getClass();
        Method[] methods = target.getMethods();
        String methodName = proceeding.getSignature().getName();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Map<String, Object> result = new HashMap<String, Object>();
                RedisLock redisLock = method.getAnnotation(RedisLock.class);
                result.put(LOCK_PRE_FIX, redisLock.lockPrefix());
                result.put(LOCK_KEY, redisLock.lockKey());
                result.put(TIME_OUT, redisLock.timeUnit().toSeconds(redisLock.timeOut()));
                return result;
            }
        }
        return null;
    }

    /**
     * 获取第一个String类型的参数为锁的业务参数
     *
     * @param proceeding
     * @return
     */
    @Deprecated
    public String getFirstArg(ProceedingJoinPoint proceeding) {
        Object[] args = proceeding.getArgs();
        if (args != null && args.length > 0) {
            for (Object object : args) {
                String type = object.getClass().getName();
                if ("java.lang.String".equals(type)) {
                    return (String) object;
                }
            }
        }
        return null;
    }

}

使用的时候, 则需要在方法上面加上该注解即可;

----------------------------------------------------------------------------------------------------

下面是基于切面表达式的注解, 我这边用日志打印来作为例子

@Aspect
@Component
public class RequestLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);

    private ThreadLocal<OperatorLog> threadLocal = new ThreadLocal<OperatorLog>();

    private static final int maxLength = 5000;

//    @Autowired
//    private OptLogService optLogService;

    @Pointcut("execution(public * com.shuige..*.controller..*.*(..))")
    public void webRequestLog() {
    }

    // @Order(5)
    @Before("webRequestLog()")
    public void doBefore(JoinPoint joinPoint) {
        try {

            long beginTime = System.currentTimeMillis();

            //获取操作系统等信息
            StringBuffer sb = new StringBuffer();
            sb.append("操作系统名称:" + System.getProperty("os.name"));//操作系统名称
            sb.append("操作系统构架" + System.getProperty("os.arch"));//操作系统构架
            sb.append("操作系统版本" + System.getProperty("os.version"));//操作系统版本

            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String beanName = joinPoint.getSignature().getDeclaringTypeName();
            String methodName = joinPoint.getSignature().getName();
            String uri = request.getRequestURI();
            String remoteAddr = getIpAddr(request);
            String sessionId = request.getSession().getId();
            String user = (String) request.getSession().getAttribute("user");
            String httpMethod = request.getMethod();
            String params = "";
            String paramsAll = "";
//            if ("POST".equals(httpMethod)) {

            try {
                Object[] paramsArray = joinPoint.getArgs();
                ObjectMapper mapper = new ObjectMapper();
                params = mapper.writeValueAsString(paramsArray);
                paramsAll = params;
                if (!StringUtils.isEmpty(params) && params.length() > maxLength) {
                    params = params.substring(0, maxLength);
                    params = "[参数太长截取 " + maxLength + " 显示]" + params;
                }
            } catch (Exception e) {
                logger.warn("params转换失败,程序不需要处理: {}", joinPoint.getArgs());
            }
//            } else {
//                Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
//                params = paramsMap.toString();
//            }

            logger.info("uri=" + uri + "; method=" + httpMethod + "; beanName=" + beanName + "; remoteAddr=" + remoteAddr + "; user=" + user
                    + "; methodName=" + methodName + "; params=" + params);

            OperatorLog optLog = new OperatorLog();
            optLog.setBeanName(beanName);
            optLog.setCurUser(user);
            optLog.setHttpMethod(httpMethod);
            optLog.setMethod(methodName);
            optLog.setParams("" + paramsAll);
            optLog.setRemoteAddr(remoteAddr);
            optLog.setSessionId(sessionId);
            optLog.setRequestUrl(uri);
            optLog.setRequestStartTime(beginTime);
            optLog.setCreateDate(new Date());
            optLog.setUserAgent(sb.toString());

            // 目标方法不为空
            if (!StringUtils.isEmpty(methodName)) {
                // set与get方法除外
                if (!(methodName.startsWith("set") || methodName.startsWith("get"))) {
                    Class targetClass = joinPoint.getTarget().getClass();
//                    Method method = targetClass.getMethod(methodName);
                    Method method = null;
                    Method[] methods = targetClass.getMethods();
                    if (methods != null) {
                        for (Method ele : methods) {
                            if (methodName.equals(ele.getName())) {
                                method = ele;
                                break;
                            }
                        }
                    }

                    if (method != null) {
                        boolean hasAnnotation = method.isAnnotationPresent(APILog.class);

                        if (hasAnnotation) {
                            optLog.setHasAnnotation(true);
                            APILog annotation = method.getAnnotation(APILog.class);
                            String methodDescp = annotation.comment();
                        }
                    }

                }
            }

            threadLocal.set(optLog);
        } catch (Exception e) {
            logger.error("***操作请求日志记录失败doBefore()***", e);
        }
    }

    // @Order(5)
    @AfterReturning(returning = "result", pointcut = "webRequestLog()")
    public void doAfterReturning(Object result) {
        try {
            // 处理完请求,返回内容
            OperatorLog optLog = threadLocal.get();
            optLog.setResult(result == null ? null : result.toString());
            long beginTime = optLog.getRequestStartTime();
            long endTime = System.currentTimeMillis();
            long requestTime = (endTime - beginTime);
            optLog.setRequestEntTime(endTime);
            optLog.setRequestTime(requestTime);

            String strResult = optLog.getResult();
            if (!StringUtils.isEmpty(strResult) && strResult.length() > maxLength) {
                strResult = strResult.substring(0, maxLength);
                strResult = "[参数太长截取 " + maxLength + " 显示]" + strResult;
            }

            String params = optLog.getParams();
            if (!StringUtils.isEmpty(params) && params.length() > maxLength) {
                params = params.substring(0, maxLength);
                params = "[参数太长截取 " + maxLength + " 显示]" + params;
            }

            String log = "\n请求耗时:" + optLog.getRequestTime() + "ms  " + optLog.getRequestUrl() + " " + optLog.getHttpMethod() + "  **  " + optLog.getMethod() + "  **  " + params
                    + "\nRESPONSE : " + strResult;

            logger.info(log);

            // TODO 保存日志
            logger.warn("TODO  还未保存API日志: {}", "★★★★★★★★★★★★★★★★★★★★★★★★");
            if (optLog.isHasAnnotation()) {
//            optLogService.saveLog(optLog);
                try {
                    String lineSeparator = System.lineSeparator();
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
                    String filePath = "apilogs/" + simpleDateFormat.format(new Date()) + ".log";

                    createDir(filePath);
                    FileOutputStream fos = new FileOutputStream(filePath, true);
                    fos.write((optLog.getRequestUrl() + "  " + optLog.getRemoteAddr() + "  " + optLog.getBeanName() + "." + optLog.getMethod() + lineSeparator + "  " + optLog.getParams() + lineSeparator).getBytes("UTF-8"));
                    fos.flush();
                    fos.close();
                } catch (Exception e) {
                    System.out.println(e.getCause());
                }
            }
        } catch (Exception e) {
            logger.error("***操作请求日志记录失败doAfterReturning()***", e);
        }
    }


    /**
     * 获取登录用户远程主机ip地址
     *
     * @param request
     * @return
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


    // 创建目录
    private static boolean createDir(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {// 判断文件是否存在
            System.out.println("目标文件已存在" + filePath);
            return false;
        }
        if (filePath.endsWith(File.separator)) {// 判断文件是否为目录
            System.out.println("目标文件不能为目录!");
            return false;
        }
        if (!file.getParentFile().exists()) {// 判断目标文件所在的目录是否存在
            // 如果目标文件所在的文件夹不存在,则创建父文件夹
            System.out.println("目标文件所在目录不存在,准备创建它!");
            if (!file.getParentFile().mkdirs()) {// 判断创建目录是否成功
                System.out.println("创建目标文件所在的目录失败!");
                return false;
            }
        }
        try {
            if (file.createNewFile()) {// 创建目标文件
                System.out.println("创建文件成功:" + filePath);
                return true;
            } else {
                System.out.println("创建文件失败!");
                return false;
            }
        } catch (IOException e) {// 捕获异常
            e.printStackTrace();
            return false;
        }
    }
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值