Spring AOP的使用

       在应用程序中,有些功能是不适合与业务逻辑混合在一起的,否则的话不便于后期人员的维护,比如:日志、声明式事务、安全和缓存等。这些功能需要以切面的形式横贯整个程序之中,减少与业务逻辑之间的耦合度,这种做法叫做面向切面编程(AOP)。本文主要描述spring框架中的AOP是如何使用的。

1、AOP术语

AOP的术语有:通知、连接点、切点、切面、引入和织入。

通知

通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。

Spring切面可以应用5种类型的通知:

前置通知:在目标方法被调用之前调用通知功能;

后置通知:在目标方法完成之后调用通知,此时不会关心方法的输出是什么;

返回通知:在目标方法成功执行之后调用通知;

异常通知:在目标方法抛出异常后调用通知;

环绕通知:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

连接点    

连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点

切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。

切面

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

引入

引入允许我们向现有的类添加新方法或属性。可以在无需修改这些现有的类的情况下,让它们具有新的行为和状态。

织入

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。Spring AOP是以运行时期这种方式织入切面的。

2、定义切点

首先定义一个computer接口,该接口有一个playGame方法。

package com.cheng.springdemo.service;

public interface Computer {

    void playGame();

}

 

       然后编写playGame()的通知,当调用该方法时,触发对应的切点。

execution(* com.cheng.springdemo.service.Computer.playGame(..))


定义切面上面的表达式中“*”号代表匹配所有的返回值,“com.cheng.springdemo.service.Computer.playGame”是限定类名和方法名,“(..)”代表匹配所有的参数。

3、定义切面

一个玩游戏的切面,在玩游戏前,要先打开游戏,打完游戏后关闭游戏,若中途电脑有电脑,需要重启电脑。

使用非环绕通知实现切面:

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 Gamer {
    // 定义切点
    @Pointcut("execution(* com.cheng.springdemo.service.Computer.playGame(..))")
    public void playGame() {}

    // 前置通知
    @Before("playGame()")
    public void openGame() {
       System.out.println("打开游戏。。。");
    }

    // 返回通知
    @AfterReturning("playGame()")
    public void closeGame() {
       System.out.println("关闭游戏。。。");
    }

    // 异常通知
    @AfterThrowing("playGame()")
    public void restartComputer() {
       System.out.println("重启电脑。。。");
    }

}

       使用环绕通知实现切面:

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 Gamer {
    // 定义切点
    @Pointcut("execution(* com.cheng.springdemo.service.Computer.playGame(..))")
    public void playGame() {}

    // 环绕通知
    @Around("playGame()")
    public void playGame(ProceedingJoinPoint jp) {
       try {
           System.out.println("打开游戏。。。");
           jp.proceed();
           System.out.println("关闭游戏。。。");
       } catch (Throwable e) {
           System.out.println("重启电脑。。。");
       }
    }

}

 

4、切面的配置类

在配置类里面配置该切面:

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

import com.cheng.springdemo.common.aop.Gamer;

/**
 * spring 切面配置
 * @author hrc
 * @date 2019年8月30日
 */
@Configuration
// 启用切面代理,声明这个配置类里面配置的bean是切面
@EnableAspectJAutoProxy
@ComponentScan("com.cheng.springdemo")
public class SpringAopConfig {
    @Bean
    public Gamer gamer() {
       return new Gamer();
    }

}


5、测试所配置的切面

       要测试我们所配置的切面,得先实现computer接口,代码如下:

import org.springframework.stereotype.Component;

import com.cheng.springdemo.service.Computer;

@Component
public class NotebookComputer implements Computer {

    @Override
    public void playGame() {
       System.out.println("用笔记本电脑玩游戏......");
    }

}

 

       然后,编写单元测试方法,代码如下:

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

import com.cheng.springdemo.common.springconfig.SpringAopConfig;
import com.cheng.springdemo.service.Computer;

@ContextConfiguration(classes = SpringAopConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class AopTest {
    @Autowired
    private Computer computer;

    @Test
    public void test1() {
       computer.playGame();
    }
}

 

       最后测试结果如下图所示:

Spring AOP的使用_第1张图片

你可能感兴趣的:(spring)