SpringAOP用法

假设你们公司的系统里面有一个匿名意见版块,所有人可以在上面匿名发表自己的意见,且意见可以被所有人看到。有一天,你的老板突然找到你,说要在匿名意见版块里面增加一个功能:将提意见者的真名和他的意见打印在后台日志里。你一边感慨老板的阴险,一边默默照做。
起初你想到直接在业务层里面打印这段日志,但感觉这样代码有所耦合,然后你又想到增加一个拦截器来打印日志,但是拦截器一般是做拦截校验的,与这个功能似乎不太匹配,突然灵光一闪你想到了可以用AOP来实现这个功能。

引入jar包:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

原先service层的代码:

@Service
public class UserServiceImpl implements IUserService {
	/**
	 * 匿名建议
	 * @param suggestion 建议内容
	 */
	@Override
	public void anonymousSuggestion(String suggestion) {
	    //省略业务逻辑
		System.out.println("将意见存入数据库");
	}
	
}

在springboot的启动类上添加@EnableAspectJAutoProxy,然后创建添加切面类

@Aspect
@Component
@Slf4j
public class ExampleAspect {
	@Before("execution(public void com.czx.xxr.service.IUserService.anonymousSuggestion(String))")
	public void log() {
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String suggestion = request.getParameter("suggestion");
        String username = (String)request.getSession().getAttribute("username");//用户名存在session中
//        log.info(username + "-提出意见:"+ suggestion);
        System.out.println(username + "-提出意见:"+ suggestion);
	}
}

调用这个接口之后控制台打印出的结果:
在这里插入图片描述
可以看到,切面类的log()方法已经在service层的anonymousSuggestion(String)方法之前被执行了。
AOP面向切面编程,我的理解就是在代码的执行流程中间插入一个切面,这个切面中有多个切点,每一个切点其实就是一个方法,当代码流程经过切面时,先执行切点的方法,然后再继续执行下去。比如上面的例子,原本的代码执行流程是:控制器层→业务层→持久层,要添加一个打印日志的功能,我也可以直接在业务层中添加打印日志的代码,但是这样的话就是在业务层中加入了一段与业务处理无关的代码,增加了代码耦合。而我用AOP注解@Before的方式就相当于在控制器层和业务层之间架起了一个切点,代码的执行流程就变为了控制器层→切点→业务层→持久层,这样一来,我就把打印日志的功能放在这个切面层里,减少了代码的耦合。

SpringAOP的概念介绍

  • Aspect (切面)用@Aspect注解加在一个类上来声明这个类是一个切面类,切面类上还需要使用@Component将其标记未一个Bean。再切面中可以包含一些切点(Pointcut)和通知(Advice)
  • Pointcut (切点)。用@Pointcut注解加在一个方法上用来声明一个切点,切点的名字就是方法名
  • Joint point(连接点)也就是业务流程在运行过程中需要插入切面的具体位置。
  • Advice(通知)是切面的具体实现方法。可分为前置通知@Before、后置通知@AfterReturning、异常通知@AfterThrowing、最终通知@After和环绕通知@Around五种。
  • Target(目标对象)被一个或者多个切面所通知的对象。
  • Proxy(代理对象)
  • Weaving(切入,也叫织入)将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期。

我将ExampleAspect类稍作改造

@Aspect
@Component
@Slf4j
public class ExampleAspect {
    @Pointcut("execution(public void com.czx.xxr.service.IUserService.anonymousSuggestion(String))")//切点表达式
	public void shareCut() {
        //这个方法不需要方法体,方法名就是切点名称
    }
	
	@Before("shareCut()")
	public void log() {
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String suggestion = request.getParameter("suggestion");
        String username = (String)request.getSession().getAttribute("username");//用户名存在session中
//        log.info(username + "-提出意见:"+ suggestion);
        System.out.println(username + "-提出意见:"+ suggestion);
	}
}

我将原来@Before()注解中的切点表达式放在了@Pointcut()注解中,然后将@Before()中的表达式改为shareCut()(即切点名称)
在这里插入图片描述
上面这个切点会匹配在 IUserService类中 anonymousSuggestion方法的调用,并且需要该方法是 public 的,只有一个 Long 的参数。

匹配字符串中可以支持一些通配符:
在这里插入图片描述

切点中的指示器

切点的表达式以 指示器 开始, 指示器 就是一种关键字,用来告诉 Spring AOP 如何匹配连接点,Spring AOP 提供了以下几种指示器:

  • execution() 用于匹配连接点的执行方法,其实就是定义拦截哪些方法
  • within() 限制连接点匹配指定的类型
  • @annotation 限定匹配带有指定注解的连接点
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值