//OK所以一个Spring增强(advisor)=切面(advice)+切入点(PointCut)
表示式(expression)和签名(signature)
//Pointcut表示式
@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
//Point签名
private void log(){}
由下列方式来定义或者通过 &&、 ||、 !、 的方式进行组合:
execution:用于匹配方法执行的连接点;
within:用于匹配指定类型内的方法执行;
this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
@within:用于匹配所以持有指定注解类型内的方法;
@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
@annotation:用于匹配当前执行方法持有指定注解的方法;
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中后面跟着“?”的是可选项
括号中各个pattern分别表示:
常用的方法:
当使用@Around处理时,需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。
@AfterReturning(
pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",
returning="returnValue")
public void access(Date time, Object returnValue, String name) {
System.out.println("目标方法中的参数String = " + name);
System.out.println("目标方法中的参数Date = " + time);
System.out.println("目标方法的返回结果returnValue = " + returnValue);
}
表达式中增加了args(time, name)部分,意味着可以在增强处理的签名方法(access方法)中定义"time"和"name"两个属性。这两个形参的类型可以随意指定(access方法中指定),但一旦指定了这两个参数的类型,则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为String的方法(方法参数个数和类型若有不同均不匹配);access方法只需要满足"time", "name"参数的顺序和pointcut中args(param1, param2)的顺序相同即可,"returnValue"位置顺序无所谓。
//将被access方法匹配
public String accessAdvice(Date d, String n) {
System.out.println("方法:accessAdvice");
return "aa";
}
正常:
优先级高的切面类里的增强处理的优先级总是比优先级低的切面类中的增强处理的优先级高。
在“进入”连接点时,最高优先级的增强处理将先被织入(eg.给定的两个不同切面类Before增强处理中,优先级高的那个会先执行);在“退出”连接点时,最高优先级的增强处理会最后被织入(eg.给定的两个不同切面类After增强处理中,优先级高的那个会后执行)。eg.优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入。
Spring提供了如下两种解决方案指定不同切面类里的增强处理的优先级:
同一个切面类里的两个相同类型的增强处理在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,没有办法指定它们的织入顺序。即使给这两个 advice 添加了 @Order 这个注解,也不行!
spring的xml开启AOP配置:
package com.noob.aspectj;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.noob.annotation.OpLog;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OpLog {
/**
*
* 操作类型
*/
int opModule();
/**
*
* 是否批量
*/
String batch();
/**
*
* 操作来源(页面+操作)
*/
String source();
}
@Aspect
@Slf4j
public class OpLogAspectj {
@Pointcut(value = "@annotation(com.noob.annotation.OpLog)")
public void methodPointcut(){}
/**
* 对带注解@OpLog的方法进行切面,并获取到注解的属性值
*/
@Around(value= "methodPointcut() && @annotation(opLog)" , argNames="opLog")
public Object around(ProceedingJoinPoint point, OpLog opLog) throws Throwable{
Object obj = null;
Object[] args = point.getArgs();
try {
obj = point.proceed(args);
} catch (Throwable e) {
log.error("方法执行异常", e);
}
long endTime = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) point.getSignature();
String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
return obj;
}
@Pointcut(value = "@annotation(org.apache.shiro.authz.annotation.RequiresPermissions)")
public void methodPointcut2(){}
/**
* 配置指定位置指定类型的参数
*/
@Around(value= "methodPointcut2() && (args(request, ..) || args(.., request))")
public Object around2(ProceedingJoinPoint point, HttpServletRequest request) throws Throwable{
Object obj = null;
Object[] args = point.getArgs();
try {
SsoUser ssoUser = SsoSession.getCurrentUser(request);
obj = point.proceed(args);
} catch (Throwable e) {
log.error("方法执行异常", e);
}
return obj;
}
}
进入切面的方法:
@OpLog(batch = YesOrNo.NO, source = FuncPointEnum.GROUP_ADD)
public Response add(RuleGroupModifyReq addModel) {
// do somethings
}
@RequestMapping(value = "/delete")
@ResponseBody
@RequiresPermissions("rule:delete")
public Response delete(
@RequestBody Map params,
HttpServletRequest request) {
// do somethings
}