一、导包
需要引入jar包:aspectjweaver.jar aspectjrt.jar(maven方式可以直接复制maven库的引用地址)
二、后台代码
@Aspect
@Component
public class Aopconfig {
@Autowired
private HttpSession session;
@Pointcut("execution(* com.*.service..save*(..)))")
public void pointTwo(){}
@Before("pointOne()")
public void doExecutionAspect(){
System.out.println("前置通知");
}
@AfterThrowing("pointTwo()")
public void dow(){
System.out.println("异常");
}
@AfterReturning("pointTwo()")
public void dd(JoinPoint joinPoint) {
System.out.println("后置通知");
}
// /**
// * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
// * @return
// */
// @Around(value="execution(* com.*.service..save*(..))")
// public Object aroundMethod(ProceedingJoinPoint jp){
// String methodName = jp.getSignature().getName();
// Object result = null;
// try {
// System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
// //执行目标方法
// result = jp.proceed();
// System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
// } catch (Throwable e) {
// System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
// }
//
// System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
// return result;
// }
三、用法
@Aspect
这是必须要的,告诉Spring这个类是执行AOP的类。如果你是用纯注解的方式,那么这个是必须的。
@Component
这是把普通pojo实例化到spring容器中,相当于配置文件中的。如果不加入,Spring 会无法将切面类实例化。
@Autowired
对类成员变量、方法及构造函数进行标注,完成自动装配的工作,消除 set ,get方法,不用在xml引用的标签。
@Pointcut(“execution(* com..service…save(…)))”)
@Pointcut主要是告诉AOP拦截的方式,execution是如何进行拦截。
public void pointTwo(){}这是个poincut的签名,方便后面四个注解使用。
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
1)括号中各个pattern分别表示
- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
- 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者 *代表所有,
- set* 代表以set开头的所有方法
- 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String)
- 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
- 异常类型匹配(throws-pattern?) 其中后面跟着“?”的是可选项
2)使用方法的配置
1)execution(* *(..))
//表示匹配所有方法
2)execution(public * com. abc.service.UserService.*(..))
//表示匹配com.abc.server.UserService中所有的公有方法
3)execution(* com.abc.server..*.*(..))
//表示匹配com.abc.server包及其子包下的所有方法
四、注解方式使用
也可以将pointcut表达式放在一个类里
package com.abc.aop;
import org.aspectj.lang.annotation.*;
public class Pointcuts {
@Pointcut("execution(* *Message(..))")
public void logMessage(){}
@Pointcut("execution(* *Attachment(..))")
public void logAttachment(){}
@Pointcut("execution(* *Service.*(..))")
public void auth(){}
}
在使用上面定义Pointcut时,指定完整的类名加上Pointcut签名就可以了,如:
package com.abc.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class LogBeforeAdvice {
@Before("com.abv.aop.Pointcuts.logMessage()")
public void before(JoinPoint joinPoint) {
System.out.println("Logging before " + joinPoint.getSignature().getName());
}
}
@AfterThrowing 是异常通知,拦截异常信息。
@Around 是环绕通知,目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码。JoinPoint joinPoint可用。
**@Before 是前置通知,目标方法执行之前执行以下方法体的内容 **
@After 是后置通知,在所拦截方法执行之后执行一段逻辑,不管是否发生异常。
@AfterReturning 是返回通知,目标方法正常执行完毕时执行以下代码。JoinPoint joinPoint可用。
XML配置
<!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 -->
<context:component-scan base-package="扫描的包"/>
<!-- 激活自动代理功能-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
最初我是用@around这个方法,但是拦截之后,无法正常执行方法,这个我到现在都没有解决,我换成了@AfterReturning。
提示:如果你要获得登录的ID,无法再dd( HttpSession session),会报错
@Autowired private HttpSession session;
最后如果你还想了解如何使用,建议你搜索JoinPoint、PropertyUtils和Method如何使用,两者可以帮住你拦截执行这个方法传出的值。例如:
Object[] args=joinPoint.getArgs();
//输出拦截的类以及所在的目录位置。
System.out.println(joinPoint.getSignature().getDeclaringTypeName().toString());
//获取ID,同理可以定义不同String获取实体类的值,这是个笨方法,更好的方法是通过反射,遍历类的每个字段,动态生成日志语句,目前我没有实现。
Long id=Long.valueOf(PropertyUtils.getProperty(object, "id").toString());
如果项目的包名不规范,可以这样子写
execution(* com.*.service..save*(..)))
或者
execution(* com.*.*.service..save*(..)))
在你想适配的service包前有几层结果就用几个.*
代替,最后要记得方法如果没有指定方法则*.*
结尾。
PS:不完全原创,参考部分博客的写法。