Java切面编程 aop 自定义注解联合使用
示例需求:需要对某些接口统一增加数据上报 ,上报数据为部分入参字段,以及部分返参字段,
步骤一 : 定义自定义标签3个
标签1: 用于标识哪些接口需要上报
标签2: 用于标识入参对象哪些属性需要上报
标签3: 用于标识出参对象哪些属性需要上报
步骤二 : 定义一个切面拦截标签1标示的接口通过反射获取对于字段的值上报信息
标签1示例代码:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoubleActiveMarkerMethod {
}
标签2示例代码:
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DoubleActiveParamKey {
// 例如:token映射到商户号,则token为key,商户号为value dto.setValue(${value});
String[] keys() default {};
}
注解2的使用方式
@Getter
@Setter
@ToString(callSuper = true)
@DoubleActiveParamKey(provider = "example-hessian", keyPrefix = "refundOrder", keys = {"orderId", "token","refundOrderId"})
public class RefundRequestDTO extends BaseRequestDTO implements Serializable {
/**
* 原交易订单号
*/
@NotBlank(message = ErrorMessageConstant.REQUEST_ID_BLANK)
@Size(max = 64, message = ErrorMessageConstant.REQUEST_ID_WRONG)
private String orderId;
/**
* 退款订单号
*/
@Size(max = 64, message = ErrorMessageConstant.REFUND_REQUEST_ID_IS_WRONG)
@NotBlank(message = ErrorMessageConstant.REFUND_REQUEST_ID_IS_BLANK)
private String refundOrderId;
...........
}
标签3示例代码:
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DoubleActiveParamValue {
String[] values() default {};
String provider() default "example-hessian";
String keyPrefix() default "examplePrefix";
}
@Getter
@Setter
@ToString(callSuper = true)
@DoubleActiveParamValue(values = {"uniqueRefundNo", "refundOrderId"})
public class RefundResponseDTO extends BaseResponseDTO {
private static final long serialVersionUID = 1L;
private String refundOrderId;
private String uniqueRefundNo;
private BigDecimal refundAmount;
......
步骤二 : 定义一个切面拦截标签1标示的接口通过反射获取对于字段的值上报信息
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@Aspect
@Component
public class DoubleActiveProxy {
private Logger logger = LoggerFactory.getLogger(DoubleActiveProxy.class);
private static final UnifierTradeClient unifierTradeClient = new UnifierTradeClient();
/**
* DoubleActiveProxy
*
* @param pjp
* @throws Throwable
*/
@Around("@annotation(DoubleActiveMarkerMethod)")
public void doAroundDoubleActiveData(ProceedingJoinPoint pjp) throws Throwable {
final List<MapperDto> mapperDtoList = new LinkedList<MapperDto>();
try {
final Iterator<Object> var1 = Arrays.stream(pjp.getArgs()).iterator();
while (var1.hasNext()) {
final Object pjpArg = var1.next();
Class<? extends Object> pjpArgClazz = pjpArg.getClass();
if (pjpArgClazz.isAnnotationPresent(DoubleActiveParamKey.class)) {
DoubleActiveParamKey doubleActiveParamKey = (DoubleActiveParamKey)
pjpArgClazz.getAnnotation(DoubleActiveParamKey.class);
//
final String[] doubleActiveKeys = doubleActiveParamKey.keys();
final Iterator<String> var2 = Arrays.stream(doubleActiveKeys).iterator();
while (var2.hasNext()) {
String[] doubleActiveKey = {var2.next()};
String clazzFieldValue = this.getClazzFieldValue(pjpArgClazz, doubleActiveKey, pjpArg);
if (null != clazzFieldValue) {
MapperDto mapperDto = new MapperDto();
// set provider and KeyPrefix
mapperDto.setKeyPrefix(doubleActiveParamKey.keyPrefix());
mapperDto.setProvider(doubleActiveParamKey.provider());
//set everyone active key
mapperDto.setKey(StringUtils.defaultIfNull(clazzFieldValue));
mapperDtoList.add(mapperDto);
}
}
}
}
//continue handle process
Object proceed = pjp.proceed();
final Class<? extends Object> clazz = proceed.getClass();
String doubleActiveValue = null;
if (clazz.isAnnotationPresent(DoubleActiveParamValue.class)) {
DoubleActiveParamValue doubleActiveParamValue = (DoubleActiveParamValue)
clazz.getAnnotation(DoubleActiveParamValue.class);
// get field value
doubleActiveValue = getClazzFieldValue(clazz, doubleActiveParamValue.values(), proceed);
}
//set everyone active values
final Iterator<MapperDto> var4 = mapperDtoList.iterator();
while (null != doubleActiveValue && var4.hasNext()) {
var4.next().setValue(StringUtils.defaultIfNull(doubleActiveValue));
}
///asynchronous batch report data
asyncBatchReportTradeUnifier(mapperDtoList);
} catch (Throwable var5) {
logger.error("double active interception failed!", var5);
throw var5;
}
}
/**
* 异步上传数据
* @param mapperDtoList
*/
private void asyncBatchReportTradeUnifier(final List<MapperDto> mapperDtoList) {
try {
AsyncThreadPoolUtil.getThreadPool().execute(
new AbstractAsyncTask("batchReportSync") {
@Override
public void execute() {
try {
boolean batchReportSync = unifierTradeClient.batchReportSync(mapperDtoList);
if (!batchReportSync) {
logger.warn("batchReportSync report data! batchReportSync:{}, mapperDtoList:{}", batchReportSync, mapperDtoList);
}
} catch (Throwable var2) {
logger.error("batchReportSync exception! mapperDtoList:{}" + mapperDtoList + " ", var2);
}
}
}
);
} catch (Throwable var3) {
logger.error("batchReportSync threadPoll run exception! mapperDtoList:{}" + mapperDtoList + " ", var3);
}
}
/**通过反射递归获取属性的值
* @param clazz
* @param doubleActiveParamKeys
* @param pjpArg
* @return
* @throws Throwable
*/
private String getClazzFieldValue(final Class<?> clazz, final String[] doubleActiveParamKeys,
final Object pjpArg) throws Throwable {
Class<?> clazzVar = clazz;
Boolean isFirstKey = Boolean.TRUE;
StringBuffer sb = new StringBuffer();
do {
isFirstKey = getThisClazzFieldValue(isFirstKey, sb, clazzVar, doubleActiveParamKeys, pjpArg);
// find parent class
clazzVar = clazzVar.getSuperclass();
}
while (null != clazzVar);
// not found field ,
if (isFirstKey) {
return null;
}
return sb.toString();
}
/**
* 获取属性值
* @param isFirstKey
* @param sb
* @param clazz
* @param doubleActiveParamKeys
* @param pjpArg
* @return
* @throws Throwable
*/
private Boolean getThisClazzFieldValue(Boolean isFirstKey, StringBuffer sb, final Class<?> clazz,
final String[] doubleActiveParamKeys, final Object pjpArg) throws Throwable {
Field[] declaredFields = clazz.getDeclaredFields();
//get keyValue by field
if (null != doubleActiveParamKeys && doubleActiveParamKeys.length > 0) {
Iterator<String> var1 = Arrays.stream(doubleActiveParamKeys).iterator();
while (var1.hasNext()) {
String doubleActiveParamKey = var1.next();
Iterator<Field> var2 = Arrays.stream(declaredFields).iterator();
while (var2.hasNext()) {
Field field = var2.next();
//get one field key
if (StringUtils.equals(field.getName(), doubleActiveParamKey)) {
field.setAccessible(Boolean.TRUE);
sb.append(isFirstKey ? field.get(pjpArg) : (":" + field.get(pjpArg)));
isFirstKey = Boolean.FALSE;
}
}
}
}
return isFirstKey;
}
/**
* 需上报的数据dto
*/
public class MapperDto {
String provider;
String keyPrefix;
String key;
String value;
public String getProvider() {
return provider;
}
public void setProvider(String provider) {
this.provider = provider;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}