【AOP】Spring AOP基础 + 实践 完整记录

简介: Spring AOP的基础概念 ============================================================= AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。

 

Spring AOP的基础概念

 

=============================================================

 AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.
在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。

==============================================================

基础概念图:

 

有了上面这张原理图,那么关于AOP面向切面编程的核心几个概念,就可以顺利铺开了:

1》join point【连接点】

在spring aop中,认为原有代码中所有的方法都是join point。

2》point cut【切点】

在不改变原有代码的情况下,想多干点事情,那就需要定义point cut,切点。切点的任务是通过一组表达式来匹配要在哪个join point切入,并且匹配要在这个join point的什么位置切入。

3》advice【增强逻辑】

根据1,2切入了原有代码后,要做些什么事情?这多做的事情就是advice,也就是多处理的一些逻辑。比如,你的原有方法是对数据的保存方法,项目交付后,新需求是需要将这些保存操作在日志中记录下来,并且不能更改原有代码,这就是增强逻辑。

advice增强逻辑你是准备放在原有代码之前还是之后,有以下几种:

  • before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)

  • after return advice, 在一个 join point 正常返回后执行的 advice

  • after throwing advice, 当一个 join point 抛出异常后执行的 advice

  • after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.

  • around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.

4》weaving【织入】

现在有了原有代码,有了新的增强逻辑。将这两部分代码连接在一起的过程,就是织入weaving。

根据不同的实现技术, AOP织入有三种方式:

    • 编译器织入, 这要求有特殊的Java编译器.

    • 类装载期织入, 这需要有特殊的类装载器.

    • 动态代理织入, 在运行期为目标类添加增强(Advice)生成子类的方式.
      Spring 采用动态代理织入, 而AspectJ采用编译器织入和类装载期织入.

5》Target【目标对象】

原有代码和增强逻辑织入在一起,重新生成的就是目标对象Target,也叫adviced object.

Spring Aop使用运行时代理的方式实现Aspect,因此adviced object是一个代理对象。

在 Spring AOP 中, 一个 AOP 代理是一个 JDK 动态代理对象或 CGLIB 代理对象。】

注意, adviced object 指的不是原来的类, 而是织入 advice 后所产生的代理类.

 【关于java中代理的概念,类型,区别和理解:

  https://www.cnblogs.com/hongcong/p/5806024.html

  https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

  可以去看上面两篇文章,我自己还没有心思去研究。

  但我记住了一句话:CGLIB方式不能代理final类。也就是说Spring AOP的切口不能切在final类上了

  】

6》aspect【切面】

aspect切面,是由point cut和advice组合而成的。既包含了连接点也就是切点的定义,也有增强逻辑的具体实现。

 

===========================================

到这里,一个概念就顺利的出来了:Spring AOP就是负责实施切面的框架, 它将切面所定义的横切逻辑织入到切面所指定的连接点中.

===========================================

 

Spring Aop的实现和使用的各种情况

 

=======================================================

要在Spring中通过注解方式使用AOP,需要下面两步:

1》在配置文件中配置

   <!-- 自动扫描注解 -->
    <context:component-scan base-package="com.sxd" />
    <!--Spring aop 使用注解的方式-->
    <aop:aspectj-autoproxy />

 

2》定义切面【aspect】

  切面包括 切点【point cut】 和  增强逻辑【advice】

  【下面aspect中已经显示了point cut的各种定义表达式   和  各种类的advice】

  【具体使用,应该按照实际使用逻辑选择性使用即可!!!】

package com.sxd.aop;

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

import java.util.Objects;


/**
 * 切面定义
 * ①在类上定义@Aspect和@Component
 * ②@Pointcut()定义切点
 * ③adive方法上,声明在哪一个切点上切入 加入增强逻辑
 */
@Aspect
@Component
public class Aspects {

    /**
     * execution()    表达式:用来匹配执行方法的连接点
     * 【..(两个点)代表零个或多个】
     * 【本例子中  第一个*代表方法的返回值类型可以为任何类型 如果本方法为void,也符合切入条件】
     * 【本例子中  第一个..代表controller包以及子包下】
     * 【本例子中  第二个*代表这个包下的任意类】
     * 【本例子中  第三个*代表这个包下的任意类中的任意方法】
     * 【本例子中  第二个..代表有无参数都可以被切入】
     *
     * args     如果想要切入的方法的参数要符合什么类型的话
     * 【本例子代表入参中,第一个参数类型需要为String类型的才会被切入,之后有零个入参或多个入参】
     *
     */
    @Pointcut(value = "execution(* com.sxd.controller..*.*(..)) && args(String,..)")
    public void pointCut1(){}


    /**
     * within()     表达式用于匹配这个包下的任意类
     */
    @Pointcut(value = "within(com.sxd.controller.*)")
    public void pointCut2(){}

    /**
     * this()       表达式限定了匹配这个类的实例下的方法
     */
    @Pointcut(value = "this(com.sxd.controller.MainController)")
    public void pointCut3(){}

    /**
     * bean()       匹配IOC容器中的bean的名称
     */
    @Pointcut(value = "bean(memberService)")
    public void pointCut4(){}












    /**
     * 下面是各种advice的展示
     *
     * 1》advice的执行优先级:  around方法执行前》before》【方法自己】》around方法执行后》after》afterReturning
     * 2》若有异常
     * advice的执行优先级:around方法执行前》before》【方法自己】》around方法执行后》after》afterReturning
     * 很奇怪为什么两次都是一样的执行优先级,为什么没有进afterThrowing().因为使用了around。
     * 3》注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!
     *
     * 4》注意:在切面的advice里面,一定不要让异常抛出去,影响原方法的执行和返回。
     * 5》JoinPoint 即原方法的入参
     * 6》returning即原方法的返回值
     * 7》如果原方法没有返回值,而这里的advice定义了returning,即使pointCut可以匹配上切点,也不会切入原方法
     */


    @Before("pointCut1()")
    public void justBefore(JoinPoint joinPoint){
        System.out.println("切入方法前");
    }


    @After("pointCut1()")
    public void justAfter(JoinPoint joinPoint){
       Object[] arr = joinPoint.getArgs();
       if(Objects.nonNull(arr) && arr.length >0){
           System.out.println((String)arr[0]);
           System.out.println((Integer)arr[1]);
       }
        System.out.println("切入方法后");
    }

    @AfterReturning(pointcut = "pointCut1()",returning = "returnVal")
    public  void justAfterReturn(JoinPoint joinPoint,Object returnVal){
        System.out.println(returnVal.toString());
        System.out.println("在方法执行完,并未抛异常,能正确返回值的情况下,在返回值之前切入");
    }

    @AfterThrowing(pointcut = "pointCut1()",throwing = "err")
    public  void justAfterThrow(JoinPoint joinPoint,Throwable err){
        System.out.println("在方法执行,抛异常的情况下,切入");
    }

    @Around("pointCut1()")
    public Object justAround(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕型切入,方法执行前");
        Object a = null;
        try {
             a =  proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕型切入,方法执行后");
        return  a;
    }

}

 

 

3》上面两步 就把aop写完了 ,最后要测试一下各种情况

package com.sxd.controller;

        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MainController {

    @ResponseBody
    @RequestMapping("do")
    public String doSomething(){
        return "无参";
    }

    @ResponseBody
    @RequestMapping("do2")
    public String doSomething2(String a){
        return "有参"+a;
    }

    @ResponseBody
    @RequestMapping("do3")
    public String doSomething3(Integer a,String b){ return "整数"+a+"---字符串"+b; }

    @ResponseBody
    @RequestMapping("do4")
    public String doSomething4(String a,Integer b){
        return "字符串"+a+"---整数"+b;
    }

    @ResponseBody
    @RequestMapping("do5")
    public String doSomething5(String a,Integer b) throws Throwable{
        return "字符串转成数字"+Integer.parseInt(a)+"---整数"+b;
    }

    @ResponseBody
    @RequestMapping("do6")
    public void doSomething6(){
        System.out.println("无返回值的");
    }
}
View Code

发请求  测试即可。

 

相关文章
|
11天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
1月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
37 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
17天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
23天前
|
数据采集 Java 数据安全/隐私保护
Spring Boot 3.3中的优雅实践:全局数据绑定与预处理
【10月更文挑战第22天】 在Spring Boot应用中,`@ControllerAdvice`是一个强大的工具,它允许我们在单个位置处理多个控制器的跨切面关注点,如全局数据绑定和预处理。这种方式可以大大减少重复代码,提高开发效率。本文将探讨如何在Spring Boot 3.3中使用`@ControllerAdvice`来实现全局数据绑定与预处理。
58 2
|
26天前
|
SQL Java 数据库
Spring Boot与Flyway:数据库版本控制的自动化实践
【10月更文挑战第19天】 在软件开发中,数据库的版本控制是一个至关重要的环节,它确保了数据库结构的一致性和项目的顺利迭代。Spring Boot结合Flyway提供了一种自动化的数据库版本控制解决方案,极大地简化了数据库迁移管理。本文将详细介绍如何使用Spring Boot和Flyway实现数据库版本的自动化控制。
24 2
|
13天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
27 0
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
72 2
|
1月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
45 0
|
前端开发 Java 数据库连接
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。