【SpringBoot应用篇】【AOP+注解】SpringBoot使用Aspect AOP基于注解获取方法形参
需求: 需要保存的日志内容在方法的参数中,并且方法参数的类型对象不一样,且对象的属性名称不一样。
【SpringBoot应用篇】SpringBoot使用Aspect AOP注解实现日志管理(增强版)
这一篇文章已经给出了解决方法。但是如果方法的参数不同,会出来转换器类爆炸的情况。
解决思路: 通过反射技术实现动态获取方法参数
1、@LogPro注解中添加field目标属性字段
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogPro {
String desc() default "";
String[] field() default "";
}
2、LogAspectPro切面增强
@Component
@Aspect
public class LogAspectPro {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAspectPro.class);
@Pointcut("@annotation(cn.zysheep.anno.LogPro)")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Map<String, Object> paramMap = new HashMap(16);
Parameter[] parameters = method.getParameters();
Object[] parameterValues = joinPoint.getArgs();
if (parameters != null && parameters.length > 0) {
for (int i = 0; i < parameters.length; ++i) {
Map<String, Object> subPlaceholder = this.getAttrs(parameters[i], parameterValues[i]);
paramMap.putAll(subPlaceholder);
}
}
LogPro logPro = method.getAnnotation(LogPro.class);
if (logPro != null) {
String[] field = logPro.field();
String str = (String)paramMap.get(field[0]);
LOGGER.info("str:{}", str);
}
}
/**
* 获取参数
* @param parameter
* @param value
*
* @return
*/
private Map<String, Object> getAttrs(Parameter parameter, Object value) {
Map<String, Object> map = new HashMap<>();
if (parameter.getType().getClassLoader() == null) {
map = this.getJdkTypeAttrs(parameter, value);
} else {
map = this.getCustomObjAttrs(value);
}
return map;
}
/**
* 获取jdk自带类型的参数
* 8种基本数据类型、List、Map
* @param parameter
* @param value
*
* @return
*/
private Map<String, Object> getJdkTypeAttrs(Parameter parameter, Object value) {
Map<String, Object> map = new HashMap<>();
if (value instanceof Integer
|| value instanceof Long
|| value instanceof Short
|| value instanceof Float
|| value instanceof Byte
|| value instanceof String
|| value instanceof Boolean
|| value instanceof Double) {
map.put(parameter.getName(), value);
return map;
}
if (value instanceof List) {
map.putAll(this.getCustomObjAttrs(((List) value).get(0)));
return map;
}
if (value instanceof Map) {
map.putAll((Map<? extends String, ?>) value);
return map;
}
LOGGER.error("参数类型不支持 type:{}", parameter.getType().getName());
return map;
}
/**
* 获取自定义对象类型的参数
*
* @param object
* @return
*/
private Map<String, Object> getCustomObjAttrs(Object object) {
Map<String, Object> map = new HashMap(16);
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
if (fields != null && fields.length != 0) {
int length = fields.length;
for (int i = 0; i < length; ++i) {
Field field = fields[i];
try {
field.setAccessible(true);
Object value = field.get(object);
if (value != null) {
map.put(field.getName(), value);
}
} catch (Exception e) {
LOGGER.warn("读取属性失败", e);
}
}
return map;
} else {
return map;
}
}
/**
* 判断一个类是JAVA类型还是用户定义类型
* @param clz
* @return getClassLoader()为null是JAVA类型
*/
private static boolean isJavaClass(Class<?> clz) {
return clz != null && clz.getClassLoader() == null;
}
}
问题:Java反射中Parameter的getName后得到arg0的问题
解决方法:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>