JAVA开发(AOP之ProceedingJoinPoint)

这篇具有很好参考价值的文章主要介绍了JAVA开发(AOP之ProceedingJoinPoint)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们在开发过程中经常使用到自定义注解来实现在一些类或者方法执行过程中切面,统一实现某些业务操作。例如自定义注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CtgEncrypt {

    /** 参数类型  */
    Class<?> paramType() default Map.class;

    /** 加密类型 (AES/RSA) */
    String securityType() default "AES";

    /**返回参数Request /响应参数Response */
    String reType() default "";

}

注解一般开门见山,说我要干一个什么事情。使用@interface来修饰。例如上面这个注解就是用来对方法上的参数进行加密的。

@Target({ElementType.METHOD,ElementType.TYPE})

这个代码作用的METHOD(方法)上

@Retention(RetentionPolicy.RUNTIME)

这个代码代码运行时执行操作。

自定义的注解需要实现它功能才能用,不是注解了注解本身就有这个功能,没那么强大。

第二步实现注解功能。

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import com.alibaba.fastjson.JSONObject;

import cn.ctg.common.response.ResponseCode;
import cn.ctg.common.response.ResponseData;
import cn.ctg.common.util.UserTokenUtils;
import cn.ctg.common.util.XssUtils;
import cn.hutool.json.JSONUtil;

/**
 * 切面,实现注解
 */
@Aspect
@Component
public class SecurityAspect {

    @Value("${keys.aeskey:-1}")
    private String AES_KEY;

    @Value("${keys.jwtkey:-1}")
    private String JWT_KEY;

    @Value("${xss.url:-1}")
    private String xxsUrl;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**切面*/
    @Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")
    public void pointCut(){ }

    /**
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* cn.ctg.*.controller.*.*(..))")
    public Object doAroundHtml(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        HttpServletRequest httpServletRequest = UserTokenUtils.getHttpServletRequest();
        String requestURI = httpServletRequest.getRequestURI();
        String[] split = xxsUrl.split("\\|");
        if(split==null){
            return joinPoint.proceed(args);
        }
        if(pathMatcher(Arrays.asList(split),requestURI)) {
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                Map<String, Object> map = JSONUtil.parseObj(JSONObject.toJSONString(arg));
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    if (XssUtils.isStripXSS(entry.getValue().toString())) {
                        ResponseData<Object> responseData = ResponseData.error(ResponseCode.XSS_CODE_ERROR);
                        return responseData;
                    }
                }
            }
        }
        return joinPoint.proceed(args);
    }

    /** 返回参数加密*/
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //执行方法,获取返回值
        Object result = joinPoint.proceed();
        String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
        if(data.equals("{}")){
            data = String.valueOf(((ResponseData<?>) result).getData());
        }

        /** 可以根据注解选择 加密方法 防止统一*/
        ((ResponseData<?>) result).setEncrypt(true);
        return result;
    }

    // 白名单查询
    private boolean pathMatcher(List<String> urlList, String requestUri) {
        for (String url : urlList) {
            if (antPathMatcher.match(url, requestUri)) {
                return true;
            }
        }
        return false;
    }

}

代码中的这一句 @Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")

就是用来实现CtgEncrypt这个注解的

再使用@Around("pointCut()")进行方法环绕。实现注解的动作。

    /** 返回参数加密*/
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //执行方法,获取返回值
        Object result = joinPoint.proceed();
        String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
        if(data.equals("{}")){
            data = String.valueOf(((ResponseData<?>) result).getData());
        }

        /** 可以根据注解选择 加密方法 防止统一*/
        ((ResponseData<?>) result).setEncrypt(true);
        return result;
    }

这是我们看到一个重要类型ProceedingJoinPoint。执行当前切点的意思

这里就通过源码看看ProceedingJoinPoint能做什么东西。

/*******************************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution and is available at
 * http://eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * initial implementation              Alexandre Vasseur
 *******************************************************************************/
package org.aspectj.lang;

import org.aspectj.runtime.internal.AroundClosure;

/**
 * ProceedingJoinPoint exposes the proceed(..) method in order to support around advice in @AJ aspects
 *
 * @author Alexandre Vasseur
 */
public interface ProceedingJoinPoint extends JoinPoint {

    /**
     * The joinpoint needs to know about its closure so that proceed can delegate to closure.run().
     * This internal method should not be called directly, and won't be visible to the end-user when
     * packed in a jar (synthetic method).
     *
     * @param arc the around closure to associate with this joinpoint
     */
    void set$AroundClosure(AroundClosure arc);

    /**
     * The joinpoint needs to know about its closure so that proceed can delegate to closure.run().
     * This internal method should not be called directly, and won't be visible to the end-user when
     * packed in a jar (synthetic method). This should maintain a stack of closures as multiple around
     * advice with proceed are targeting a joinpoint and the stack will need to be unwound when
     * exiting nested advice. Passing a non null arc indicates a push, passing null indicates a pop.
     *
     * @param arc the around closure to associate with this joinpoint
     */
     default void stack$AroundClosure(AroundClosure arc) {
         throw new UnsupportedOperationException();
     }

    /**
     * Proceed with the next advice or target method invocation
     *
     * @return the result of proceeding
     * @throws Throwable if the invoked proceed throws anything
     */
    public Object proceed() throws Throwable;

    /**
     * Proceed with the next advice or target method invocation.
     *
     * Unlike code style, proceed(..) in annotation style places different requirements on the 
     * parameters passed to it.  The proceed(..) call takes, in this order:
     * <ul>
     * <li> If 'this()' was used in the pointcut for binding, it must be passed first in proceed(..).
     * <li> If 'target()' was used in the pointcut for binding, it must be passed next in proceed(..) - 
     * it will be the first argument to proceed(..) if this() was not used for binding.
     * <li> Finally come all the arguments expected at the join point, in the order they are supplied 
     * at the join point. Effectively the advice signature is ignored - it doesn't matter 
     * if a subset of arguments were bound or the ordering was changed in the advice signature, 
     * the proceed(..) calls takes all of them in the right order for the join point. 
     * </ul>
     * Since proceed(..) in this case takes an Object array, AspectJ cannot do as much 
     * compile time checking as it can for code style. If the rules above aren't obeyed 
     * then it will unfortunately manifest as a runtime error. 
     *
     * @param args the arguments to proceed with
     * @return the result of proceeding
     * @throws Throwable if the invoked proceed throws anything
     */
    public Object proceed(Object[] args) throws Throwable;

}


从源码上继承了JoinPoint

proceedingjoinpoint获取返回值,java,java,微服务,Powered by 金山文档

public Object proceed() throws Throwable;

Proceed with the next advice or target method invocation

继续执行下一个通知或目标方法调用

proceedingjoinpoint获取返回值,java,java,微服务,Powered by 金山文档

获取当前正在执行的对象(如果不可用则为空——例如静态上下文)

Object getThis();

获取目标对象(如果没有,则为空)

Object getTarget();

获取这个连接点上的参数

Object[] getArgs();

获取连接点上的签名。

Signature getSignature();文章来源地址https://www.toymoban.com/news/detail-560714.html

到了这里,关于JAVA开发(AOP之ProceedingJoinPoint)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包