一.定义切面
1.在Spring中使用注解定义切面,我们会用到下面的注解:
注解 | 通知 |
---|---|
@Aspect | 它标识一个类是一个切面 |
@After | 它标识的通知方法会在目标方法返回或抛出异常后调用 |
@AfterReturning | 它标识的通知方法会在目标方法返回后调用 |
@AfterThrowing | 它标识的通知方法会在目标方法抛出异常后调用 |
@Around | 通知方法会将目标方法封装起来 |
@Before | 通知方法会在目标方法调用之前执行 |
我们知道切面由切点和通知构成。(切点定义在上篇boke中)
下面我们来学习一个例子:
@Aspect//标识此类是一个切面
public class Audience{
//标识次方法会在perform()方法执行之前执行
@Before("execution(** concert.Performance.perform(..))")
public void silenceCellPhones(){
System.out.println("Silencing cell phones");
}
//标识次方法会在perform()执行之后执行
@AfterReturning("execution(** concert.Performance.perform(..))")
public void applause(){
System.out.println("Clap Clap");
}
}
2.上面的例子中标识每个方法我们都要写一样的切点表达式不免让我们感觉有些繁琐,我们可以通过下面的注解来简化上面的代码:
@Pointcut 能在一个@AspectJ切面内定义可重用的切点。
有了它,上面的代码可以写成:
@Aspect//标识此类是一个切面
public class Audience{
//定义可重用切点
@Pointcut("execution(** concert.Performance.perform(..))")
public void performance(){}//它是一个空方法,它主要是提供一个标识
//标识次方法会在perform()方法执行之前执行
@Before("performance()")
public void silenceCellPhones(){
System.out.println("Silencing cell phones");
}
//标识次方法会在perform()执行之后执行
@AfterReturning("performance()")
public void applause(){
System.out.println("Clap Clap");
}
}
可以大大简化代码量。
二.使切面生效
上面的代码只是定义了一个切面,如果就此止步的话,上面定义的类就只是Spring容器的一个bean,即使用了切面注解,它也不会被视为切面,这些注解不会解析,也不会创建将其转换为切面的代理。
所以我们下一步要做的是:让我们定义的切面生效:
//启动AspectJ自动代理
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig{
//声明Audience bean
@Bean
public Audience audience(){
return new Audience();
}
}
这样以后,我们的切面才会生效。
三.创建环绕通知
环绕通知是最为强大的通知类型,它能让你所编写的逻辑被通知的目标方法完全包装起来。(实际上就像在一个通知方法中同时编写前置通知和后置通知)
我们使用@Around来实现:
@Aspect//标识此类是一个切面
public class Audience{
//定义可重用切点
@Pointcut("execution(** concert.Performance.perform(..))")
public void performance(){}//它是一个空方法,它主要是提供一个标识
//标识环绕通知方法
@Around("performance()")
public void watchPerformance(ProceedingJoinPoint jp){
try{
System.out.println("Silencing cell phones");
jp.proceed();
System.out.println("Clap Clap");
}catch(Throwable e)
{
System.out.println("发生异常");
}
}
}
我们可以看到,这个通知所达到的效果和前面的一样,但是它们在这里位于同一个方法中,不像之前分散在几个方法里。
关于上面方法,我们发现多了一个ProceedingJoinPoint 类型的参数,这个对象必须要有的,因为它的作用就是通过它来调用被通知的方法,好让我们的目标方法执行。