spring实现自定义注解切面编程
例如要实现在某几个类之后或之前调用一些操作,就可以用到这个
1. 创建自定义注解
import java.lang.annotation.*;
//注解放置的位置,METHOD是放在方法上
@Target(ElementType.METHOD)
//注解在哪个阶段执行
@Retention(RetentionPolicy.RUNTIME)
//生成文档
@Documented
public @interface ElaSearchRefresh {
String id() default "";
String className() default "";
}
类中只需要写上自己需要的字段即可,后面可以作为传参使用
2. 引入注解变量解析util
照抄就完了
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 该类的作⽤可以把⽅法上的参数绑定到注解的变量中
* 注解的语法
* 变量名
* #{}
* 能解析类似
* "#{sysOperateLogDto.operateType}"
*/
public class AnnotationResolver {
private static AnnotationResolver resolver;
public static AnnotationResolver newInstance() {
if (resolver == null) {
return resolver = new AnnotationResolver();
} else {
return resolver;
}
}
/**
* 解析注解上的值
*
* @param joinPoint 需要解析的字符串
* @param str
* @return
*/
public Object resolver(JoinPoint joinPoint, String str) {
if (str == null) return null;
Object value = null;
//如果匹配上了#则把内容当作变量
if (str.matches("#\\{\\D*\\}")) {
String newStr = str.replaceAll("#\\{", "").replaceAll("\\}", "");
if (newStr.contains(".")) {//复杂类型
try {
value = complexResolver(joinPoint, newStr);
} catch (Exception e) {
e.printStackTrace();
}
} else {
value = simpleResolver(joinPoint, newStr);
}
} else {//⾮变量
value = str;
}
return value;
}
private Object complexResolver(JoinPoint joinPoint, String str) throws Exception {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String[] names = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
boolean jsonParseFlag = false;
if (str.startsWith("$JSON$")){
jsonParseFlag = true;
str = str.replace("$JSON$","");
}
String[] strs = str.split("\\.");
for (int i = 0; i < names.length; i++) {
if (strs[0].equals(names[i])) {
Object obj = args[i];
if (obj instanceof Map){
return ((Map<?, ?>) obj).get(strs[1]);
}
//支持json解析
if (obj instanceof String && jsonParseFlag){
JSONObject jsonObject = JSON.parseObject(obj.toString());
return jsonObject.get(strs[1]);
}
Method dmethod = obj.getClass().getDeclaredMethod(getMethodName(strs[1]));
Object value = dmethod.invoke(args[i]);
return getValue(value, 1, strs);
}
}
return null;
}
private Object getValue(Object obj, int index, String[] strs) {
try {
if (obj != null && index < strs.length - 1) {
Method method = obj.getClass().getDeclaredMethod(getMethodName(strs[index + 1]));
obj = method.invoke(obj);
getValue(obj, index + 1, strs);
}
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getMethodName(String name) {
return "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
}
private Object simpleResolver(JoinPoint joinPoint, String str) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String[] names = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
for (int i = 0; i < names.length; i++) {
if (str.equals(names[i])) {
return args[i];
}
}
return null;
}
}
3. 创建切面类
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.*;
@Aspect
@Component
public class ElaSearchAspect {
@Autowired
private IBaseDao baseDao;
//定义切点
@Pointcut(value = "@annotation(net.zjsos.business.common.business.filebase.aspect.ElaSearchRefresh)")
public void elaRefreshPointCut() {
}
//定义切面
@After("elaRefreshPointCut()")
//around需要使用ProceedingJoinPoint point
public void after(JoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
ElaSearchRefresh annotation = method.getAnnotation(ElaSearchRefresh.class);
//利用util来反射解析动态变量属性
String id = AnnotationResolver.newInstance().resolver(point, annotation.id()).toString();
//如果是写死的变量,直接使用annotation.id()获取即可
}
//定义切面
@Around("elaRefreshPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
//去执⾏被访问的切⾯
Object result = point.proceed();
//从切⾯织⼊点处通过反射机制获取织⼊点处
MethodSignature signature = (MethodSignature) point.getSignature();
//获取切⼊点所在的方法
Method method = signature.getMethod();
ElaSearchRefresh annotation = method.getAnnotation(ElaSearchRefresh.class);
//利用util来反射解析动态变量属性
String id = AnnotationResolver.newInstance().resolver(point, annotation.id()).toString();
//如果是写死的变量,直接使用annotation.id()获取即可
}
}
4. 使用注解
@RequestMapping("/updateAccessByApplyId")
//获取动态变量需要加"#{}",写死的变量直接"xxx"就行了
@ElaSearchRefresh(id = "#{dto.id}")
public ResultDto updateAccessByApplyId(@RequestBody @Valid FileBaseUpdateAccessDto dto){
xxxxxxxxxxxxxxxxxxxxxx
}
分别是哔哩哔哩序号35,小米运动序号2,米友社序号13,这个是同一个账号下运行的任务