JoinPoint 对象
连接点,Spring AOP 的JoinPoint就是对这个连接点的抽象,Spring中接入点一般是方法。
@Before(value = "@annotation(com.changhong.yyhl.spider.worker.aop.SpiderParam)")
public void param(JoinPoint joinPoint){
// JoinPoint 就是连接点方法的抽象,可以操作被增强位置的信息
}
JoinPoint 可得到:
被代理对象方法的参数、方法签名、返回值等信息
Object[] args = joinPoint.getArgs();
可以拿到目标对象的方法参数,这时对args的修改,就会真正的修改到真实切点方法的参数上去
JoinPoint 的增强类 => ProceedingJoinPoint
ProceedingJoinPoint pjp 配合@Around使用环绕,可以在增加方法中使用pjp.proceed()分割目标方法的 before 和 after,
.proceed()执行是把控制权交给了目标方法。
.proceed()之前执行的代码是前置增强,
.proceed()之后执行的代码是后置增强。
定位织入点位置
(1)基于注解
(2)
@Pointcut(
"execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?.name-pattern(param-pattern)throws-pattern?)"
)
modifier-pattern:表示方法的修饰符
ret-type-pattern:表示方法的返回值
declaring-type-pattern?:表示方法所在的类的路径
name-pattern:表示方法名
param-pattern:表示方法的参数
throws-pattern:表示方法抛出的异常&&
符号表示与关系,使用||
表示或关系、使用!
表示非关系
bean()描述符,是spring bean的name
解释:
其中后面跟着“?”的是可选项。
在各个pattern中,可以使用"*"来表示匹配所有。
在param-pattern中,可以指定具体的参数类型,多个参数间用“,”隔开,各个也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String)表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型。
可以用(..)表示零个或多个任意的方法参数。
例子:
excecution(* com.tianmaying.service.BlogService.updateBlog(..)) and bean('tianmayingBlog')
定义增强方法
@Before:前置通知,在调用目标方法之前执行通知定义的任务
@After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务
@After-returning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务
@After-throwing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务
@Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务
@Before(value = "controllerAspect()")
public void methodBefore(JoinPoint joinPoint){
// 执行增强方法
}
最后“定义增强方法”和“定位织入点位置”需要放到一个类中,使用@Aspect和@Compent注解
基于自定义注解@SpiderParam的例子
1 定义注解
@Target(ElementType.METHOD)//这个注解是应用在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface SpiderParam { }
2 定义切面对象
@Aspect
@Component// 切面对象任然是个对象,故扫描 public class SpiderParamAspect { private static final Logger logger = LoggerFactory.getLogger(SpiderParamAspect.class); // 通过注解来确定切点位置
@Before(value = "@annotation(com.changhong.yyhl.spider.worker.aop.SpiderParam)")
public void param(JoinPoint joinPoint) throws Throwable{
Object[] args = joinPoint.getArgs();// 下面都是增强方法,这个可以捕捉到被代理对象的参数列表
Param param = null;
for (Object arg : args){
if(arg instanceof Param){
param = (Param) arg;// 找到我们需要的预处理的参数对象
}
}
if(param == null){
return;
}
// 操作param就可以达到预处理被代理对象方法的目的
param.setXXX()
}
}
3 注解了@SpiderParam到方法被增强
4 如果在增强方法中想要取注解值
//这个注解是应用在方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
String value();
}
@Aspect
@Component
public class PermissionAspect {
// 定义基于注解的切点
@Pointcut(value = "@annotation(com.changhong.touchc.core.component.auth.Permission)")
public void pointCut(){}
// 绑定切点和注解,&&后面小写打头的permission
@Before(value = "pointCut() && @annotation(permission)")
public void doBefore(JoinPoint joinPoint, Permission permission) {
String permissionValue = permission.value();
}
}
@Permission("employeeCapacity:view")
@RequestMapping(value = "/pageInfoEmployeeInfo",method = RequestMethod.GET)
ResponseEntity getEmployeeInfo(){
}
基于@Pointcut和@Before
@Before的value值应该是@Pointcut注解的方法签名
@Pointcut("execution(......)")
void pointcutAspect()
@Before(value = "pointcutAspect()")
public void param(JoinPoint joinPoint){}