首页 > 其他分享 >Spring AOP

Spring AOP

时间:2024-05-03 19:22:36浏览次数:28  
标签:匹配 Spring 切入点 AOP 通知 方法 public

AOP简介

  • A0P(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构
    • OOP(object Oriented Programming)面向对象编程
  • 作用:在不惊动原始设计的基础上为其进行功能增强
  • Spring理念:无入侵式/无侵入式

AOP核心概念

20240503_140412_211_copy.png

  • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
    • 在SpringAOP中,理解为方法的执行
  • 切入点(Pointcut):匹配连接点的式子
    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
      • 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知(Advice):在切入点处执行的操作,也就是共性功能
    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:定义通知的类
  • 切面(Aspect):描述通知与切入点的对应关系

AOP入门

  1. 创建一个通知类,并交给Spring管理。 @Component
  2. 创建通知类。 @Aspect , 告诉Spring这是一个通知类
  3. 定义切入点:使用注解 @Pointcut
  4. 绑定切入点和通知
  5. 在配置类上加上注解: @EnableAspectJAutoProxy告诉Spring我们有注解开发的AOP
@Configuration//表示这是一个配置类  
@ComponentScan("com.fyislo")//配置扫描注解  
@PropertySource({"jdbc.properties"})//加载properties的配置文件  
@EnableAspectJAutoProxy//告诉Spring我们有注解开发的AOP  
public class SpringConfig {  
}

@Component//配置bean  
@Aspect//告诉Spring这是一个通知类  
public class MyAdvice {  
    //这是一个切入点
    @Pointcut("execution(* com.fyislo.service.Impl.BookServiecImpl.show())")  
    private void pt() {}//切入点:不需要方法体  
  
    @Before("pt()")//绑定切入点和通知
    public void method() {  
        System.out.println(System.currentTimeMillis());  
    }  
}

AOP的工作流程

  1. Spring容器启动
  2. 读取所有切面配置中的切入点(只有帮了通知的切入点才读取)
  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
    • 匹配失败,创建对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取bean执行方法
    • 获取bean,调用方法并执行,完成操作
    • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
  • 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
  • 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

SpringAOP本质:代理模式

AOP切入点表达式

  • 切入点:要进行增强的方法
  • 切入点表达式:要进行增强的方法的描述方法

语法格式

  • 切入点表达式标准格式:
    • 动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
  • 动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点
  • 访问修饰符:public,private等,可以省略
  • 返回值
  • 包名
  • 类/接口名
  • 方法名
  • 参数
  • 异常名:方法定义中抛出指定异常,可以省略

可以使用通配符描述切入点,快速描述

  • * :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
    • exection (public * com.fyislo.*.dao.show*(*))
    • 匹配com.fyislo包下的任意包中的dao类或接口所有的show开头的带有一个参数的方法
  • .. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
    • exection (public User com..UserService.show(..))
    • 匹配com包下任意包中的UserService类或接口所有名称为show的方法
  • + :专用于匹配子类类型
    • exection(* * ..*Service+.*(..))

书写技巧

  • 所有代码按照标准规范开发,否则以下技巧全部失效
  • 描述切入点通常描述接口,而不描述实现类
  • 访问控制修饰符针对接口开发均采用oublicf描述(可省略访问控制修饰符描述
  • 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用 * 通配快速描述
  • 包名书写尽量不使用..匹配,效率过低,常用 * 做单个包描述匹配,或精准匹配
  • 接口名/类名书写名称与模块相关的采用 * 匹配,例如JserService书写成 * Service,绑定业务层接口名
  • 方法名书写以动词进行精准匹配,名词采用 * 匹配,例如getByld书写成getBy * ,selectAll书写成selectAll
  • 参数规则较为复杂,根据业务方法灵活调整
  • 通常不使用异常作为匹配规则

AOP通知类型

  • AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
  • AOP通知共分为5种类型
    • 前置类型: @Before
    • 后置类型: @After
    • 环绕类型(重点): @Around
    • 返回后通知(了解):
    • 抛出异常后通知(了解): @Af
//前置通知
@Before("pt()")
public void before(){
	System.out.println("before");
}

//后置通知
@After("pt()")
public void after(){
	System.out.println("after");
}

//环绕通知
//通过ProceedingJoinPoint对原始方法进行调用,并且获得一个返回值
@Around("pt()")
public object around(ProceedingJoinPoint pjp)throws Throwable {
	System.out.println("around before");
	Object ret = pjp.proceed();
	System.out.println("around after");
	return ret;
}

//方法运行结束后,运行此方法
@AfterReturning("pt()")
public void afterReturning(){
	System.out.println("afterReturning");
}

//方法出异常的时候运行
@AfterThrowing("pt()")
public void afterThrowing(){
	System.out.println("afterThrowing");
}
  • @Around 注意事项
    1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    2. 通知中如果未使用ProceedingJoinPointi对原始方法进行调用将跳过原始方法的执行
    3. 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
    4. 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
    5. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

免责声明:此片文章是个人学习笔记,存在借鉴引用和模仿,若有冒犯或侵权,联系可更改或删除。

标签:匹配,Spring,切入点,AOP,通知,方法,public
From: https://www.cnblogs.com/fyislo/p/18171516

相关文章

  • Spring 中 bean 的生命周期
    Spring中的bean指的是被IoC管理的对象,通常都是以DI的方式来使用,并不需要手动管理它们的生命周期。但是,有时候我们需要对特定的bean进行额外的初始化、销毁操作,此时就可以通过Spring中的拓展接口来实现。基本生命周期Spring中IoC的顶层接口是BeanFactory,默认实现......
  • 解决创建SpringBoot工程加载较慢的问题
    设置ServerURL将https://start.spring.io改为https://start.aliyun.com如图所示:启动演示如图所示,启动成功......
  • SpringBoot3.1.5对应新版本SpringCloud开发(1)-Eureka注册中心
    服务的提供者和消费者服务之间可以通过Spring提供的RestTemplate来进行http请求去请求另一个Springboot的项目,这就叫做服务间的远程调用。当一个服务通过远程调用去调用另一个服务时,被调用的服务就叫做服务的提供者,调用服务的服务就叫做服务的消费者。一个服务可以既是服务的提......
  • 蚂蚁面试:Springcloud核心组件的底层原理,你知道多少?
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • springboot+MDCAdapter自定义starter实现日志全链路追踪
    MDCMDC(MappedDiagnosticContext,映射调试上下文)是日志系统提供的一种方便在多线程条件下记录日志的功能使用场景一个常用的场景就是Web服务器中给每个请求都分配一个独特的请求id,所有的日志都会打印这个请求id,这样一个请求下的所有日志信息都可以很方便的找到。欢迎关注个人公......
  • SpringBoot中分页插件PageHelper的使用
    SpringBoot如何使用PageHelper实现分页查询在原始的分页查询方法中,需要编写复杂的SQL语句来限制查询结果的范围,通常需要使用LIMIT或者ROWNUM等数据库特定的语法来实现分页。在每个需要分页的查询方法中,都需要手动计算分页的起始位置和偏移量,通常需要根据页码和每页数量来计算,这部......
  • Field registration in org.springframework.cloud.client.serviceregistry.ServiceRe
    Fieldregistrationinorg.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration$ServiceRegistryEndpointConfigurationrequiredasinglebean,but2werefound: -nacosRegistration:definedbymethod'nacosRegistration'in......
  • SpringMVC(2)-Rest请求风格
    REST:RepresentationalStateTransfer,(资源)表现层状态转化。REST是目前流行的请求方式。在HTTP协议中,有四个基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。REST就是通过get/post/put/delete说明crud的类型。REST的核心过滤器浏览器form表单......
  • [springboot]配置文件加载顺序
    一般项目直接使用.jar文件以server.port配置举例;以jar包内和jar包外说明内部和外部配置文件顺序由高到底,如下:外部-启动时指定参数外部-环境变量外部config/yml文件外部yml文件内部config/yml文件内部yml文件启动时,如果指定了激活的profile文件,会优先找激活的profile文......
  • [springboot] application.yml是变灰色的,不支持输入提示
       检查是否存在插件:springbootassistant,springbootFile->Setting; plugins,查看右侧“Installed”不存在则安装springbootassistant默认插件中如果没有找到springbootassistant,安装springassistant插件效果如下,显示为有绿色的图标 内容也支持输入提示......