Java注解实现动态拼接参数

现有需求
@Log(description = "{a}查询 {b} 的数据")
动态拼接参数保存到数据库中,就像 redis 缓存中 key 的动态拼接,@Cacheable(value="RptGroupAgent",key="'localAgentName'+#localAgentName") 。
接下来我们通过自定义注解来实现这个功能。
新增注解
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

String  methodDesc() </span><span style="color: rgba(0, 0, 255, 1)">default</span> ""<span style="color: rgba(0, 0, 0, 1)">;

String  description() </span><span style="color: rgba(0, 0, 255, 1)">default</span> ""<span style="color: rgba(0, 0, 0, 1)">;

}

 对应的 AOP

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAdvice {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Logger logger=LoggerFactory.getLogger(LogAdvice.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

@Pointcut(</span>"@annotation(注解路径)"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> serviceAspect() {
}

@After(</span>"serviceAspect()"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> after(JoinPoint joinPoint) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
    logger.info(</span>"开始记录日志*************************"<span style="color: rgba(0, 0, 0, 1)">);

    MethodSignature ms </span>=<span style="color: rgba(0, 0, 0, 1)"> (MethodSignature) joinPoint.getSignature();
    Method method </span>=<span style="color: rgba(0, 0, 0, 1)"> ms.getMethod();

    Log myAnnotation </span>= method.getAnnotation(Log.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

    Map</span>&lt;String,Object&gt; paramsMap = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
    String[] argNames </span>= ((MethodSignature)joinPoint.getSignature()).getParameterNames(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数名</span>
    Object[] argObjects = joinPoint.getArgs(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数</span>
    List&lt;String&gt; argNameList =<span style="color: rgba(0, 0, 0, 1)"> Arrays.asList(argNames);
    resolveArgs(joinPoint,argNameList,argObjects,paramsMap);

    saveToDbLog(myAnnotation,paramsMap);
}

@AfterReturning(pointcut </span>= "serviceAspect()",returning="returnValue"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> afterreturningJoinPoint(JoinPoint joinPoint ,Object returnValue){

// System.out.println("后置通知"+joinPoint+"返回值"+returnValue);
}

@Around(</span>"serviceAspect()"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Object around(ProceedingJoinPoint pjp) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Throwable{
    Object object </span>=<span style="color: rgba(0, 0, 0, 1)"> pjp.proceed();
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> object;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> saveToDbLog(Log myAnnotation, Map&lt;String,Object&gt;<span style="color: rgba(0, 0, 0, 1)"> paramsMap){
    String description </span>=<span style="color: rgba(0, 0, 0, 1)"> myAnnotation.description();
    description </span>=<span style="color: rgba(0, 0, 0, 1)"> handleAnnotation(description,paramsMap);
    System.out.println(description);<br>     //TODO db操作
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String handleAnnotation(String description, Map&lt;String,Object&gt;<span style="color: rgba(0, 0, 0, 1)"> paramsMap){
    AtomicReference</span>&lt;String&gt; result = <span style="color: rgba(0, 0, 255, 1)">new</span> AtomicReference&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">(description);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtils.isBlank(description)){
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result.get();
    }
    paramsMap.entrySet().parallelStream().forEach(p</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">{
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(result.get().contains(p.getKey())){
            result.set(result.get().replaceAll(p.getKey(), p.getValue() </span>+ ""<span style="color: rgba(0, 0, 0, 1)">));
        }
    });
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result.get();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> resolveArgs(JoinPoint joinPoint, List&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)"> argNameList, Object[] argObjects,
                               Map</span>&lt;String,Object&gt;<span style="color: rgba(0, 0, 0, 1)"> paramsMap){
    </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; argNameList.size(); i++<span style="color: rgba(0, 0, 0, 1)">){
        Class</span>&lt;?&gt; classo =<span style="color: rgba(0, 0, 0, 1)"> argObjects[i].getClass();

        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(handleClassType(classo.getName())){
            paramsMap.put(argNameList.get(i),joinPoint.getArgs()[i]);
            </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
        }
    </span><span style="color: rgba(0, 0, 0, 1)">
        JSONObject object </span>=<span style="color: rgba(0, 0, 0, 1)"> (JSONObject) JSONObject.toJSON(joinPoint.getArgs()[i]);

        object.keySet().parallelStream().forEach(p</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">{
            paramsMap.put(p,object.get(p));
        });
    }

}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span>  &lt;T&gt; T get(Class&lt;T&gt;<span style="color: rgba(0, 0, 0, 1)"> clz,Object o){
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(clz.isInstance(o)){
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> clz.cast(o);
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}


</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> handleClassType(String name){
    AtomicBoolean result </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> AtomicBoolean(<span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
    String[] className </span>= {"String","Integer","Long","int","float","double","char"<span style="color: rgba(0, 0, 0, 1)">};
    Arrays.asList(className).forEach(n</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">{
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(name.contains(n)) {
            result.set(name.contains(n));
        }
    });
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result.get();
}

}