Skip to content

Spring AOP 使用切面

🏷️ Spring

1. Maven 配置文件 ( pom.xml ) 中添加依赖

xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>liujiajia-me</groupId>
        <artifactId>liujiajia-me-spring-learn</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>liujiajia-me-spring-learn-aop</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>1.5.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2. 创建一个演奏接口(定义一个切点 perform

java
package concert;

/**
* Created by liujiajia on 2017/3/28.
*/
public interface Performance {
    public void perform();
}

3. 创建实现类

java
package concert;

import org.springframework.stereotype.Component;

/**
* Created by liujiajia on 2017/3/28.
*/
@Component
public class MusicConcert implements Performance {
    public void perform() {
        System.out.println("Playing music");
    }
}

4. 定义切面

使用 @Aspect 注解标记为切面。

使用 @After @AfterReturning @AfterThrowing @Around @Before 注解来声明通知方法,参数为切点表达式。可以使用 @Pointcut 注解来声明频繁使用的切点表达式。

java
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.springframework.stereotype.Component;

/**
* Created by liujiajia on 2017/3/28.
*/
@Aspect
@Component
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");
    }
}

5. 在 JavaConfig 中使用 @EnableAspectJAutoProxy 注解启用 AspectJ 注解的自动代理

java
package concert;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
* Created by liujiajia on 2017/3/28.
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {

}

6. 创建测试类

java
package concert;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertEquals;

/**
* Created by liujiajia on 2017/3/28.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ConcertConfig.class)
public class AudienceTest {
    @Autowired
    private Performance performance;

    @Test
    public void performance() {
        performance.perform();
    }
}

7. 测试结果

Silencing cell phones
Taking seats
Playing music
CLAP CLAP CLAP!!!

8. 使用 @Pointcut 标注声明频繁使用的切点表达式

java
package concert;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
* Created by liujiajia on 2017/3/28.
*/
@Aspect
@Component
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");
    }
}

9. 使用 @Around 环绕通知

java
package concert;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
* Created by liujiajia on 2017/3/28.
*/
@Aspect
@Component
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");
        }
    }
}