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><String,Object> paramsMap = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><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<String> 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<String,Object><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<String,Object><span style="color: rgba(0, 0, 0, 1)"> paramsMap){ AtomicReference</span><String> result = <span style="color: rgba(0, 0, 255, 1)">new</span> AtomicReference<><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>-><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<String><span style="color: rgba(0, 0, 0, 1)"> argNameList, Object[] argObjects, Map</span><String,Object><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 < argNameList.size(); i++<span style="color: rgba(0, 0, 0, 1)">){ Class</span><?> 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>-><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> <T> T get(Class<T><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>-><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(); }
}