在类上使用 @Aspect 注解 使之成为切面类
public class CheckAspect {
//前置通知,在方法执行前通知
@Before("execution(* com.igeek.service.impl.ClientServiceImpl.getAll(..))")
public void checkBeforeLog(JoinPoint joinpoint){
System.out.println("我是验证切面的前置通知"+joinpoint);
}
}
- @Before 标示前置通知 。指的意思是 在特定位置之前 去执行该方法 。
- 通知 其实就是切面类中一个具体的方法 。
- 使用前置通知注解。 在目标方法开始之前执行。
execution
JoinPoint 标示连接点 。
com.igeek.service.impl.ClientServiceImpl.getAll(..))")
可以使用AspectJ表达式,对目标方法进行抽象概括。
- 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法
第二个* 表示当前包下所有的类
第三个* 表示所有的方法名称
.. 表示匹配任意多个参数。
(String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
String,String 表示匹配参数为两个字符串的方法。
如果调用的同一个类的某个方法,不想重复的写路径,也可以进行封装,例:
@Pointcut("execution(* com.igeek.service.impl.*.*(..))")
public void declareRepeatJoinPointExpression(){
}
前置通知
@Before("declareRepeatJoinPointExpression()")
public void beforeLog(JoinPoint joinpoint){
//通过连接点对象可以获得调用目标方法的名称以及参数。
//获得方法名称。 能拿到你要调用的方法的名字 。
String method = joinpoint.getSignature().getName();
//获得调用方法时传递的参数。
List arguments = Arrays.asList(joinpoint.getArgs());
//System.out.println("前置日志。。。调用了:"+method+"方法,参数是:"+arguments);
System.out.println("前置日志。");
}
后置通知,注:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。
@After("declareRepeatJoinPointExpression()")
public void afterLog(JoinPoint joinpoint){
String method = joinpoint.getSignature().getName();
List arguments = Arrays.asList(joinpoint.getArgs());
System.out.println("后置日志 。");
}
返回通知,注:返回通知 ,其实跟后置通知一样 。都是在目标方法执行完之后 才会被执行
@AfterReturning(value="execution(* com.igeek.service.impl.*.*(..))",returning="sb")
//注:returning="sb" 名字 要跟参数列表中 Object 对象的名称一致 ,不然产生异常。
public void testAfterReturning(JoinPoint joinpoint,Object sb){
String method = joinpoint.getSignature().getName();
System.out.println("我是返回通知 。 我在目标方法核心业务执行完才会执行 。"+sb);
}
异常通知 。
@AfterThrowing(value="execution(* com.igeek.service.impl.*.count())",throwing="e")
public void testAfterThrowing(JoinPoint joinpoint,Exception e){
System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
}
环绕通知 .跟动态代理的代码很像。
@Around("execution(* com.igeek.service.impl.ClientServiceImpl.getAll())")
public void around(ProceedingJoinPoint pjp){
//声明一个Object 对象 用来表示 目标方法的返回值 。
Object result = null;
String methodName=pjp.getSignature().getName();
try {
System.out.println("我是前置日志 。。。"+methodName);
result=pjp.proceed();
System.out.println("我是返回通知 。。。"+result+methodName);
//Throwable 所有异常类跟错误类的父类 。Exception Error ...
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
}//调用proceed() 表示执行被代理类的目标方法。
System.out.println("我是后置通知 。。。"+result+methodName);
}
如果在方法前添加了注解,那么在xml文件中,只需添加如下代码:
<!-- 自动扫描组件 -->
<context:component-scan base-package="com/igeek"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
当然也利用xml语句指定方法
<aop:config>
<aop:pointcut expression="execution(* com.igeek.service.impl.*.*(..))" id="pointcut"/>
<aop:aspect ref="loggingAspect" order="1">
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("springaop.xml");
ClientService bean = (ClientService)ac.getBean("clientService");
List all = bean.getAll();
}
输出结果:
我是前置日志 。。。getAll
核心业务 getAll执行完毕...
我是返回通知 。。。[我是敖冠海叔叔]getAll
我是后置通知 。。。[我是敖冠海叔叔]getAll
所有类型的方法
@Before("declareRepeatJoinPointExpression()")
public void beforeLog(JoinPoint joinpoint){
//通过连接点对象可以获得调用目标方法的名称以及参数。
//获得方法名称。 能拿到你要调用的方法的名字 。
String method = joinpoint.getSignature().getName();
//获得调用方法时传递的参数。
List arguments = Arrays.asList(joinpoint.getArgs());
//System.out.println("前置日志。。。调用了:"+method+"方法,参数是:"+arguments);
System.out.println("前置日志。");
}
///注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。
@After("declareRepeatJoinPointExpression()")
public void afterLog(JoinPoint joinpoint){
String method = joinpoint.getSignature().getName();
List arguments = Arrays.asList(joinpoint.getArgs());
System.out.println("后置日志 。");
}
//注意:返回通知 ,其实跟后置通知一样 。都是在目标方法执行完之后 才会被执行 。
//returning="sb" 名字 要跟参数列表中 Object 对象的名称一致 ,不然产生异常。
//返回通知 : xml 注解 。
//@AfterReturning(value="execution(* com.igeek.service.impl.*.*(..))",returning="sb")
public void testAfterReturning(JoinPoint joinpoint,Object sb){
//
String method = joinpoint.getSignature().getName();
System.out.println("我是返回通知 。 我在目标方法核心业务执行完才会执行 。"+sb);
}
//异常通知 。
//@AfterThrowing(value="execution(* com.igeek.service.impl.*.count())",throwing="e")
public void testAfterThrowing(JoinPoint joinpoint,Exception e){
System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
}
//环绕通知 。 跟动态代理的代码很像。
@Around("execution(* com.igeek.service.impl.ClientServiceImpl.getAll())")
public void around(ProceedingJoinPoint pjp){
//声明一个Object 对象 用来表示 目标方法的返回值 。
Object result = null;
String methodName=pjp.getSignature().getName();
try {
System.out.println("我是前置日志 。。。"+methodName);
result=pjp.proceed();
System.out.println("我是返回通知 。。。"+result+methodName);
//Throwable 所有异常类跟错误类的父类 。Exception Error ...
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
}//调用proceed() 表示执行被代理类的目标方法。
System.out.println("我是后置通知 。。。"+result+methodName);
}
}