美文网首页
Spring AOP

Spring AOP

作者: TheMrBigHead | 来源:发表于2018-09-07 06:51 被阅读0次

Spring AOP

一、面向切面编程

1. AOP术语
image.png
1.1 ADVICE(增强)
在aop中,aspect的职责(功能)被称为advice。它定义了一个aspect在什么时间应该做什么事情。

Spring提供了以下几种advice:

  1. Before 在目标的方法调用之前调用advice的功能
  2. After 在目标方法调用之后调用advice的功能
  3. After-returning 在目标方法成功调用完成后,调用advice的功能
  4. After-throwing 在目标方法抛出异常后,调用advice的功能
  5. Around 环绕增强,在目标方法之前和之后都来调用advice的功能
1.2 JOIN POINTS(连接点)
连接点是应用程序执行中可以插入切面的点
1.3 POINTCUTS(切点)
切点定义了增强在什么地方产生作用。

切点匹配一个或多个应该被注入增强的连接点的位置。

1.4 ASPECTS(切面)
切面是切点和增强的组合,它定义了增强应该在什么时间、什么地点去做什么事情
1.5 INTRODUCTIONS
 Introductions允许你向一个已经存在的类添加新的属性或方法
1.6 WEAVING(织入)
织入就是讲切面应用到目标对象上以创造一个新的代理对象的过程

织入发生在目标对象声明周期的几个时间点:

  1. 编译时
  2. 类加载时
  3. 运行时 (Spring在这个阶段织入切面)
2. Spring对AOP的支持

Spring’s support for AOP comes in four styles:

  1. Classic Spring proxy-based AOP
  2. Pure-POJO aspects
  3. @AspectJ annotation-driven aspects
  4. Injected AspectJ aspects (available in all versions of Spring)

Spring AOP框架的一些关键点:

  1. Spring增强是试用JAVA写的,是标准的java类

  2. Spring是在运行时(runtime)增强目标对象的


    image.png
  3. Spring仅仅支持方法级别的连接点(原因是Spring AOP是基于动态代理的)

2.1 在切点中选择连接点
image.png
2.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的bean
3. 创建被注解的切面
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注解由以下三个部分组成:

  1. value 表明有几种Bean需要引入这个interface,在例子中的是Performance本身及其所有子类都需要(“+”表示自己及所有子类)
  2. defaultImpl 属性指明了一个默认的introduction interface的实现类
  3. static 被@DeclareParents注解的属性是static的,表明是一个被introduction的接口
4. 在xml配置文件里声明切面
image.png
image.png
  <!--启用自动代理-->
  <aop:aspectj-autoproxy>
image.png image.png image.png image.png image.png

相关文章

网友评论

      本文标题:Spring AOP

      本文链接:https://www.haomeiwen.com/subject/fvuxgftx.html