1.自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 横切逻辑注解
* @author xdc
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Operation{
OperType type();
}
说明:必须使用@Retention(RetentionPolicy.RUNTIME) 进行声明,否则系统启动异常。
2.注解使用
@Operation(type=OperType.DELETE)
@Override
public void deleteProject(String id) {
// 代码逻辑...
}
说明:service层接口实现类中的某个方法。
/**
* 操作类型
* @author xdc
*/
public enum OperType {
SAVE("新建"), UPDATE("更新"), DELETE("删除");
private String type;
private OperType(String type){
this.type = type;
}
public String toString(){
return type;
}
}
4.AOP中使用
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ProjectAspect {
@Before("@annotation(oper)")
public void test(JoinPoint joinPoint, Operation oper) throws Exception {
System.out.println(oper.type());
}
}
说明:@before中@annotation注解里面的值必须和下面方法里的参数对应,否则启动报错。
另一项目使用记录
1.注解
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SyncEs {
//需要的查询条件
String[] conditions() default {};
//查询条件对应的查询字段
String[] conditionKeys() default {};
//需要同步的es数据表
Class<?> esIndexClass() default ESAssetCardInfo.class;
//直接指定id同步
String indexId() default "0";
/**
* 查询条件是 and / or
* @return
*/
EsLogical esLogical() default EsLogical.AND;
}
2.枚举类
public enum EsLogical {
AND, OR
}
3.环绕增强
@Component
@Aspect
public class SyncEsAspect {
private static final Logger Log = LoggerFactory.getLogger(SyncEsAspect.class);
@Resource(name = "esCardRepository")
private EsCardRepository esCardRepository;
@Resource(name = "assetCardSearchService")
private AssetCardSearchService assetCardSearchService;
private static final ExpressionParser expressionParser = new SpelExpressionParser();
ParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private ConcurrentHashMap<String,Expression> cacheExpression = new ConcurrentHashMap<>();
@Around("within(com.xxx.cloud.assets.serviceImpl..*) && @annotation(syncEs)")
public Object syncEs(ProceedingJoinPoint joinPoint, SyncEs syncEs) throws Throwable {
try {
Object result = joinPoint.proceed();
syncEsInner(joinPoint, syncEs);
return result;
} catch (Throwable throwable) {
throw throwable;
}
}
private void syncEsInner(ProceedingJoinPoint joinPoint, SyncEs syncEs) {
// 切面所在类
Object target = joinPoint.getTarget();
String methodName = joinPoint.getSignature().getName();
Method method = null;
for (Method m : target.getClass().getMethods()) {
if (m.getName().equals(methodName)) {
method = m;
break;
}
}
EvaluationContext evaluationContext = new MethodBasedEvaluationContext(target, method, joinPoint.getArgs(),
defaultParameterNameDiscoverer);
if (StringUtils.isNotEmpty(syncEs.indexId())) {
Integer indexId = getExpression(syncEs.indexId()).getValue(evaluationContext, Integer.class);
if (indexId != null && indexId > 0) {
// 如果定义了根据id更新,更新完直接return
...
return;
}
}
String[] conditions = syncEs.conditions();
String[] conditionKeys = syncEs.conditionKeys();
EsLogical logical = syncEs.esLogical();
if (conditions == null || conditionKeys == null || conditions.length ==0 || conditions.length != conditionKeys.length) {
Log.error("无法更新数据到es,因为注解中的数据非法!");
return;
}
...
}
private Expression getExpression(String expression) {
if(cacheExpression.containsKey(expression)){
return cacheExpression.get(expression);
}else {
Expression expressionObject = null;
synchronized (SyncEsAspect.class) {
expressionObject = expressionParser.parseExpression(expression);
}
cacheExpression.put(expression,expressionObject);
return expressionObject;
}
}
}
4.使用
@Override
@SyncEs(indexId = "#model.id")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
public int saveAssetCard(AssetCardModel model, String remark) throws AssetException {
...
}