项目中有很多时候需要在所执行的方法前或者方法后执行一些特殊的逻辑代码,这个时候首先就想到了aop切面结合自定义注解来实现我想要的功能,但是注意,这种方式并不是万能的,这个放到最后说。下面请看我的代码
首先需要自定义自己的注解(这里以我的ExecAfterMethod和ExecBeforeMethod为例)
package cn.people.one.core.annotation;
import java.lang.annotation.*;
/**
* <P>方法执行后执行的注解</P>
* @author 高仕立
* @date 2019/10/18 10:36 AM
* @since
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExecAfterMethod {
/**
* 唯一标记
* @return
*/
String sign() default "";
/**
* 请求当前接口所需要的参数,多个以小写的逗号隔开
* @return
*/
String fieldNames() default "";
/**
* 传递参数的对象类型
*/
Class<?> parameter() default Object.class;
/**
* 默认不校验参数
* @return
*/
boolean require() default false;
}
package cn.people.one.core.annotation;
import java.lang.annotation.*;
/**
* <P>方法执行前执行的注解</P>
* @author 高仕立
* @date 2019/10/18 10:36 AM
* @since
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ExecBeForeMethod {
/**
* 唯一标记
* @return
*/
String sign() default "";
/**
* 请求当前接口所需要的参数,多个以小写的逗号隔开
* @return
*/
String fieldNames() default "";
/**
* 传递参数的对象类型
*/
Class<?> parameter() default Object.class;
/**
* 默认不校验参数
* @return
*/
boolean require() default false;
}
然后在需要的方法头上面添加对应的注解
/**
* 增加用户
*
* @param oriUser
*/
@Override
@Transactional
@ExecBeForeMethod(sign="UserServiceImpl:save",fieldNames = "#{oriUser}",parameter = BaseEntity.class,require = true)
public boolean save(User oriUser) {
......
return true;
}
定义切面拦截
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
/**
* <P>方法执行的切面拦截器</P>
* @author 高仕立
* @date 2019/10/18 10:40 AM
* @since
*/
@Aspect
@Component
@Slf4j
public class ExeMethodAspect {
/**
* 执行方法标记--基础类保存方法
*/
private static final String EXEC_METHOD_SIGN_SAVE = "BaseServiceImpl:save";
private static final String EXEC_METHOD_SIGN_SAVE2 = "UserServiceImpl:save";
/**
* 执行方法标记--基础类修改方法
*/
private static final String EXEC_METHOD_SIGN_UPDATE = "BaseServiceImpl:update";
private static final String EXEC_METHOD_SIGN_UPDATE2 = "UserServiceImpl:update";
@Pointcut("@annotation(ExecAfterMethod的完整路径)")
public void execAfterMethodPointCut(){
}
@Pointcut("@annotation(ExecBeForeMethod的完整路径)")
private void execBeforeMethodPointCut() {
}
@AfterReturning(pointcut = "execAfterMethodPointCut()",returning = "retValue")
public void after(JoinPoint join, Object retValue) {
log.info("---method after start---");
MethodSignature signature = (MethodSignature) join.getSignature();
Method method = signature.getMethod();
ExecAfterMethod execAfterMethod = method.getAnnotation(ExecAfterMethod.class);
if (execAfterMethod == null) {
return;
}
if (execAfterMethod.require() && StringUtils.isEmpty(execAfterMethod.fieldNames())) {
return;
}
Map<String,Object> resolver = AnnotationResolver.newInstance().resolver(join, execAfterMethod.fieldNames());
log.info("---resolver---{}",resolver);
log.info("---方法标记---{}",execAfterMethod.sign());
//添加自己的实现方法 TODO
}
@Before("execBeforeMethodPointCut()")
public void before(JoinPoint join){
//执行方法前的逻辑
log.info("---method before start---");
MethodSignature signature = (MethodSignature) join.getSignature();
Method method = signature.getMethod();
ExecBeForeMethod execBeForeMethod = method.getAnnotation(ExecBeForeMethod.class);
if (execBeForeMethod == null) {
return;
}
if (execBeForeMethod.require() && StringUtils.isEmpty(execBeForeMethod.fieldNames())) {
return;
}
//解析参数的值
Map<String,Object> resolver = AnnotationResolver.newInstance().resolver(join, execBeForeMethod.fieldNames());
log.info("---resolver---{}",resolver);
//添加自己的实现方法 TODO
if(EXEC_METHOD_SIGN_SAVE.equals(execBeForeMethod.sign()) || EXEC_METHOD_SIGN_SAVE2.equals(execBeForeMethod.sign())){
}
if(EXEC_METHOD_SIGN_UPDATE.equals(execBeForeMethod.sign()) || EXEC_METHOD_SIGN_UPDATE2.equals(execBeForeMethod.sign())){
}
}
}
定义参数解析器
package cn.people.one.config.annoation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* <P>解析自定义注解传递的参数</P>
* @author 高仕立
* @date 2019/10/18 2:01 PM
* @since
*/
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 Map<String,Object> resolver(JoinPoint joinPoint, String str) {
Map<String,Object> value = null;
if (str == null) {
return null ;
}
// 如果name匹配上了#{},则把内容当作变量
if (str.matches("\\D*#\\{\\D*\\}")) {
String newStr = str.replace(",",",").replaceAll("#\\{", "").replaceAll("\\}", "");
if (newStr.contains(",")) {
try {
value = complexResolver(joinPoint, newStr);
} catch (Exception e) {
e.printStackTrace();
}
} else {
value = simpleResolver(joinPoint, newStr);
}
} else { //非变量
return null;
}
return value;
}
private Map<String,Object> complexResolver(JoinPoint joinPoint, String str) throws Exception {
Map<String,Object> map = new HashMap<>();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String[] names = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
String[] strs = str.split(",");
for (int i = 0; i < names.length; i++) {
for(int j=0;j<strs.length; j++){
if (strs[j].equals(names[i])) {
map.put(names[i],args[i]);
// Method dmethod = obj.getClass().getDeclaredMethod(getMethodName(strs[1]), null);
// Object value = dmethod.invoke(args[i]);
// return getValue(value, 1, strs);
}
}
}
return map;
}
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]), null);
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 Map<String,Object> simpleResolver(JoinPoint joinPoint, String str) {
Map<String,Object> map = new HashMap<>();
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])) {
map.put(str,args[i]);
}
}
return map;
}
}
通过以上配置就可以实现想要的结果了;
注意:
spring AOP 对于方法内部调用不会拦截