SpringAop

Spring中有两大重心:springIoc和springAop

springioc将bean的控制权交给了spring管理,直接从spring中获取,通过五大注解来告诉spring帮我管理这个对象。通过@Autowired和构造方法和set方法注入。

不仅仅是学习重点也是面试常考的难点。

springAop(难点):

aop是面向切面编程,和面向对象编程不是互斥也不是升级,而是补充。
什么是⾯向切⾯编程呢? 切⾯就是指某⼀类特定问题, 所以AOP也可以理解为⾯向特定⽅法编程。
什么是⾯向特定⽅法编程呢? ⽐如上个章节学习的"登录校验", 就是⼀类特定问题。 登录校验拦截器, 就是对"登录校验"这类问题的统⼀处理。所以, 拦截器也是AOP的⼀种应⽤。 AOP是⼀种思想, 拦截器是AOP思想的⼀种实现。 Spring框架实现了这种思想, 提供了拦截器技术的相关接⼝。同样的, 统⼀数据返回格式和统⼀异常处理, 也是AOP思想的⼀种实现。 (我个人认为就是简称针对于大家很多时候都会遇到的一种问题进行编程,比如统一返回,对一类事情进行集中处理)。

AOP是⼀种思想, 它的实现⽅法有很多, 有Spring AOP,也有AspectJ、CGLIB等.

在这里我们想做一个Aop切面,让我们即使不用修改原本的代码也能够做到记录程序运行时间的方法。

第一步:使用AOP要先引入依赖

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

第二步:引入一个切面(一类特定问题)

package com.syx.book.aspect;

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

@Component
@Aspect
public class TimeRecordAspect {
}

引入@Aspect注解,spring使用了AspectJ(第三方的jar包,类似于lombok)注解,但是实际上是spring实现的。

package com.syx.book.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect
public class TimeRecordAspect {
    //记录耗时
    //作用范围@Around()
    @Around("execution(* com.syx.book.Controller.*.*(..))")
    public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {
        long start=System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long end=System.currentTimeMillis();
        log.info("耗时时间"+(end-start)+"ms");
        return proceed;

    }
}

这是创建了一个记录程序运行到结束的AOP类,@Around括号后边表示作用的范围:说明作用于scom.syx.book.Controller包中,后边第一个*表示所有类,第二个*表示所有方法。

在这里就可以看到,我们并没有在原本代码上面改变,但是却能够同样实现时间耗时功能。

  1. @Aspect: 标识这是⼀个切⾯类
  2. @Around: 环绕通知, 在⽬标⽅法的前后都会被执⾏. 后⾯的表达式表⽰对哪些⽅法进⾏增强.(侵入程序的时机,目标前后都会执行)
  3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏

springAop核心概念介绍:

1.切点:一种规则

Pointcut 的作⽤就是提供⼀组规则 (使⽤ AspectJ pointcut expression language 来描述), 告诉程序对哪些⽅法来进⾏功能增强。也就是@Around后边的字符串,描述了在哪里进行切入。对哪些的方法进行功能增强。(告诉哪些能被连接成切面,哪些不能被连接成切面,哪些能被Aop认识到,就是寻找匹配项)。

2.连接点:符合规则的对象

与切点的关系:切点是对连接点的一种筛选。所有的连接点构成了程序执行过程中的可能的关注点,而切点则用于从这些众多的连接点中挑选出符合特定条件的那些点,然后在这些挑选出来的连接点上应用切面的通知。

3.通知:方法内部的逻辑

表示连接点具体要做的事情(也就是方法里面咱们程序员写的逻辑等等),被叫做方法。

通知的几种类型:
  1. @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
  2. @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
  3. @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
  4. @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执行
  5. @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
4.切面:符合规则做的事情

切点+连接点+通知=切面。


通知的几种介绍:
1.before和after同理 :

这是切面的设置以及切面的逻辑

package com.syx.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;


@Slf4j
@Component
@Aspect
public class AspectDemo {
    //作用的范围是TestController
    @Before("execution(* com.syx.aop.Controller.*.*(..))")
    public void doBefore(){
        log.info("do before..........");


    }

}

package com.syx.aop.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("test")
public class TestController {
    @RequestMapping("doBefore")
    public String t1(){

        return "t1";

    }
}

下面表示调用t1方法然后就会打印日志。

doBefore是在程序执行之前打印。

2.Around

around是要求我们在切面配置的时候要求我们要返回一个object

@Around("execution(* com.syx.aop.Controller.*.*(..))")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("do Around.............");
        Object proceed = joinPoint.proceed();
        log.info("do Around.............");
        return proceed;
    }

}

Around必须要有返回函数。否则会没有返回值

在这里我们会发现假如同时配置了before after和around时候,around会优先执行。

3.AfterReturn

当接口正常的时候会先执行afterreturn

5.AfterThrowing

如果有异常的话比如在这里我们调用的时候出现了一个算数异常10/0,就不会执行AfterReturn和最后的Around而是直接执行AfterThrowing。

before和after不管咋样都会执行。

在这里的@Aspect中就有很多切面类。

6.pointcut

描述切点,在这里通过注释@pointcut描述

@Slf4j
@Component
@Aspect
public class AspectDemo {
    @Pointcut("execution(* com.syx.aop.Controller.*.*(..))")
    public void pt(){}



    //作用的范围是TestController
    @Before("pt()")
    public void doBefore(){
        log.info("do before..........");

    }

在下面在注解后写入pt()即可 。

如果其他类中需要使用这里的pt()方法必须要指定路径,,全限定路径。

如果有多个切面作用在同一个切点上,就会按照名称进行排序。这时候我们要用@order注解

7.order

数字越大级别越低,before的时候数字越小先执行。

相关推荐
fangxiang200814 分钟前
spring boot 集成 knife4j
java·spring boot
C++小厨神23 分钟前
Bash语言的计算机基础
开发语言·后端·golang
BinaryBardC26 分钟前
Bash语言的软件工程
开发语言·后端·golang
飞yu流星32 分钟前
C++ 函数 模板
开发语言·c++·算法
没有名字的鬼37 分钟前
C_字符数组存储汉字字符串及其索引
c语言·开发语言·数据结构
王先生技术栈1 小时前
思维导图,Android版本实现
java·前端
生如夏花℡1 小时前
JAVA学习记录3
java·学习·idea
专注于开发微信小程序打工人1 小时前
庐山派k230使用串口通信发送数据驱动四个轮子并且实现摄像头画面识别目标检测功能
开发语言·python
土豆凌凌七1 小时前
GO:sync.Map
开发语言·后端·golang
{⌐■_■}1 小时前
【gRPC】对称与非对称加解密和单向TLS与双向TLS讲解与go案例
java·servlet·golang