Spring AOP
一、面向切面编程
1. AOP术语
image.png1.1 ADVICE(增强)
在aop中,aspect的职责(功能)被称为advice。它定义了一个aspect在什么时间应该做什么事情。
Spring提供了以下几种advice:
- Before 在目标的方法调用之前调用advice的功能
- After 在目标方法调用之后调用advice的功能
- After-returning 在目标方法成功调用完成后,调用advice的功能
- After-throwing 在目标方法抛出异常后,调用advice的功能
- Around 环绕增强,在目标方法之前和之后都来调用advice的功能
1.2 JOIN POINTS(连接点)
连接点是应用程序执行中可以插入切面的点
1.3 POINTCUTS(切点)
切点定义了增强在什么地方产生作用。
切点匹配一个或多个应该被注入增强的连接点的位置。
1.4 ASPECTS(切面)
切面是切点和增强的组合,它定义了增强应该在什么时间、什么地点去做什么事情
1.5 INTRODUCTIONS
Introductions允许你向一个已经存在的类添加新的属性或方法
1.6 WEAVING(织入)
织入就是讲切面应用到目标对象上以创造一个新的代理对象的过程
织入发生在目标对象声明周期的几个时间点:
- 编译时
- 类加载时
- 运行时 (Spring在这个阶段织入切面)
2. Spring对AOP的支持
Spring’s support for AOP comes in four styles:
- Classic Spring proxy-based AOP
- Pure-POJO aspects
- @AspectJ annotation-driven aspects
- Injected AspectJ aspects (available in all versions of Spring)
Spring AOP框架的一些关键点:
-
Spring增强是试用JAVA写的,是标准的java类
-
Spring是在运行时(runtime)增强目标对象的
image.png -
Spring仅仅支持方法级别的连接点(原因是Spring AOP是基于动态代理的)
2.1 在切点中选择连接点
image.png2.1.1 写一个切点
package concert;
public interface Performance {
public void perform();
}
image.png
image.png
&& and
|| or
! not
2.1.2 在切点中选取Bean
选取ID为woodstock的bean 选取ID不为woodstock的bean3. 创建被注解的切面
3.1 定义切面
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;
@Aspect
public class Audience {
@Before("execution(** concert.Performance.perform(..))")
public void silenceCellPhones() {
System.out.println("Silencing cell phones");
}
@Before("execution(** concert.Performance.perform(..))")
public void takeSeats() {
System.out.println("Taking seats");
}
@AfterReturning("execution(** concert.Performance.perform(..))")
public void applause() {
System.out.println("CLAP CLAP CLAP!!!");
}
@AfterThrowing("execution(** concert.Performance.perform(..))")
public void demandRefund() {
System.out.println("Demanding a refund");
}
}
注解@Aspect表明当前类是一个切面
image.png使用@Pointcut注解来定义一个可以重用的切点
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 demandRefund() {
System.out.println("Demanding a refund");
}
}
配置切面自动代理:
@Configuration
@EnableAspectJAutoProxy // Enable AspectJ auto-proxying
@ComponentScan
public class ConcertConfig {
@Bean
public Audience audience() {
return new Audience();
}
}
或
<aop:aspectj-autoproxy>
3.2 创建一个Around Advice(环绕增强)
@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");
}
}
ProceedingJoinPoint
3.3 处理Advice里的参数
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)) " +
"&& args(trackNumber)")
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;
}
}
image.png
3.4 Annotating introductions
introductions向bean添加新的方法
image.png
package concert;
public interface Encoreable {
void performEncore();
}
package concert;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class EncoreableIntroducer {
@DeclareParents(value="concert.Performance+",
defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
@DeclareParents注解由以下三个部分组成:
- value 表明有几种Bean需要引入这个interface,在例子中的是Performance本身及其所有子类都需要(“+”表示自己及所有子类)
- defaultImpl 属性指明了一个默认的introduction interface的实现类
- static 被@DeclareParents注解的属性是static的,表明是一个被introduction的接口
4. 在xml配置文件里声明切面
image.pngimage.png
<!--启用自动代理-->
<aop:aspectj-autoproxy>
image.png
image.png
image.png
image.png
image.png
网友评论