《Spring实战》摘录 - 9
81
Q: #4.2.1-2 | 使用within()指示器限制切点范围
A:
82
Q: #4.2.1-3 | 因为“&”在XML中有特殊含义,所以在Spring的XML配置里面描述切点时用什么来替代?
A: 可以使用and来代替“&&”。同样,or和not可以分别用来代替“||”和“!”
83
Q: #4.3.1-1 | 某个类中使用@AspectJ注解的作用
A:
以Audience类为例,Audience类使用@AspectJ注解进行了标注。该注解表明Audience不仅仅是一个POJO,还是一个切面。Audience类中的方法都使用注解来定义切面的具体行为。
84
Q: #4.3.1-2 | Spring使用AspectJ注解来声明通知方法,都有哪些注解
A:
- @After - 通知方法会在目标方法返回或抛出异常后调用
- @AfterReturning - 通知方法会在目标方法返回后调用
- @AfterThrowing - 通知方法会在目标方法抛出异常后调用
- @Around - 通知方法会将目标方法封装起来
- @Before - 通知方法会在目标方法调用之前执行
85
Q #4.3.1-3 | @Pointcut注解能够在一个@AspectJ切面内定义可重用的切点。请通过@Pointcut注解声明频繁使用的切点表达式。
A:
package concert;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class Audience{
@Pointcut(“execution(** concert.Performance.perform(…))”)
public void performance(){}
@Before(“performance()”) //表演之前
public void silenceCellPhones(){
System.out.println(“Silencing cell phones”);
}
@Before(“performance()”) //表演之前
public void takeSeats(){
System.out.println(“Taking seats”);
}
@AfterReturning(“performance()”) //表演之后
public void applause(){
System.out.println(“CLAP CLAP CLAP !!!”);
}
@AfterThrowing(“performance()”) //表演失败之后
public void demandRedund(){
System.out.println(“Demanding a refund”);
}
}
86
Q: #4.3.1-4 | 在XML中,通过Spring的aop命名空间启用AspectJ自动代理
A:
<?xml version=“1.0” encoding=“UTF-8”?>
<beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:context=“http://www.springframework.org/schema/context”
xmls:aop=“http://www.springframework.org/schema/aop”
xsi:schemaLocation=“http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd“>
<context:component-scan base-package=“concert” />
<aop:aspectj-autoproxy /> //启用AspectJ自动代理
<bean class=“concert.Audience” /> //声明Audience bean
</beans>
87
Q: #4.3.2-1 | 环绕通知有什么用?
A:
环绕通知是最为强大的通知类型。它能够让你所编写的逻辑将被通知的目标方法完全包装起来。实际上就像在一个通知方法中同时编写前置通知和后置通知。
88
Q: #4.3.2-2 | 使用环绕通知重新实现Audience切面
A:
package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.PointCut;
@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”);
System.out.println(“Taking seats”);
jp.proceed();
System.out.println(“CLAP CLAP CLAP !!!”);
} catch(Throwable e){
System.out.println(“Demanding a refund”);
}
}
}
89
Q: #4.3.2-3 | 为什么说在使用环绕通知切面编程的时候,为什么说不要忘了调用processed()方法
A:
别忘记调用proceed()方法。如果不调这个方法的话,那么你的通知实际上会阻塞对被通知方法的调用。有可能这就是你想要的效果,但更多的情况是你希望在某个点上执行被通知的方法。
有意思的是,你可以不调用proceed()方法,从而阻塞对被通知方法的访问,与之类似,你也可以在通知中对它进行多次调用。要这样做的一个场景就是实现重试逻辑,也就是在被通知方法失败后,进行重复尝试。
90
Q: #4.3.3-1 | 在切面编程中,如何处理通知中的参数
A: 以“使用参数化的通知来记录磁道播放的次数”为例,代码如下:
package soundsystem;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TrackCounter {
private Map<Integer, Integer> trackCounts = new HashMap<Integer, Integer>();
@Pointcut(
“execution(* soundsystem.CompactDisc.playTrack(int)) ” + //通知playTrack()方法
“&& args(tracjNumber)” )
public void trackPlayed(int trackNumber) {}
@Before(“trackPlayed(trackNumber)”) //在播放前,为该磁到道计数
public void countTrack(int trackNumber) {
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, currentCount + 1);
}
public int getPlayCount(int trackNumber){
return trackCOunts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0;
}
}