【Spring】Spring框架之-AOP

news/2024/12/23 21:00:05 标签: spring, java, mysql

目录

1. AOP的引入

2. AOP相关的概念

2.1 AOP概述

2.2 AOP的优势

2.3. AOP的底层原理--目前先不具体阐述,后面讲

 3. Spring的AOP技术-配置文件方式

3.1 AOP相关的术语

3.2 基本准备工作

3.3 AOP配置文件方式的入门

3.4 切入点的表达式

 3.5 AOP的通知类型

1. 前置通知

2. 环绕通知

3. 最终通知

4.  后置通知

 4. Spring的AOP技术-注解方式

4.1. AOP注解方式入门程序

1. 配置xml扫描注解

2. 配置注解 

3. 配置文件中开启自动代理

4. 通知类型注解


1. AOP的引入

首先我们来看一下登录的原理

        如上图所示这是一个基本的登录原理图,但是如果我们想要在这个登录之上添加一些新的功能,比如权限校验

那么我们能想到的就有两种方法:

①:通过对源代码的修改实现 

②:不通过修改源代码方式添加新的功能 (AOP)

 


2. AOP相关的概念

2.1 AOP概述

什么是AOP的技术?

        在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程

        AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。

        AOP最早由AOP联盟的组织提出的,制定了一套规范.  Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范。

        通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术。

        AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

        利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率.

        AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(事务管理、安全检查、缓存)

为什么要学习AOP?

        可以在不修改源代码的前提下,对程序进行增强!!-->也就是增加功能

2.2 AOP的优势

运行期间,不修改源代码的情况下对已有的方法进行增强

优势:

        1. 减少重复的代码

        2. 提供开发的效率

        3. 维护方便

2.3. AOP的底层原理--目前先不具体阐述,后面讲

JDK的动态代理技术

        1、为接口创建代理类的字节码文件

        2、使用ClassLoader将字节码文件加载到JVM

        3、创建代理类实例对象,执行对象的目标方法

cglib代理技术

        为类生成代理对象,被代理类有没有接口都无所谓,底层是生成子类,继承被代理类。


 3. Spring的AOP技术-配置文件方式

3.1 AOP相关的术语

        Joinpoint(连接点) 类里面有哪些方法可以增强这些方法称为连接点。

        Pointcut(切入点) -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

        Advice(通知/增强)-- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)。

        Aspect(切面)-- 是 切入点+通知 的结合,以后咱们自己来编写和配置的。

 

        成熟的不能作为连接点,但是成熟的没见过,就是都能作为连接点。

        增加功能的代码就是增强。

        try-catch-finally,finally永远都会执行。


3.2 基本准备工作

        AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,AspectJ实际上是对AOP编程思想的一个实践。

3.3 AOP配置文件方式的入门

$1. 创建maven项目,坐标依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--AOP联盟-->
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <!--Spring Aspects-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <!--aspectj-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.3</version>
    </dependency>
</dependencies>

 注意!!

        我这里Maven配置时 aspectj 是空项目,就是之前没有下载,因此一直报错。

        如果你也一直报错,右键鼠标,点击Maven,下载资源即可解决!!

 $2. 创建被增强的类

java">public class Cat {


    public void add(int nums){
        System.out.println("添加了"+nums);
    }

    public void delete(int nums){
        System.out.println("删除了"+nums);
    }
    public void update(){
        System.out.println("进行了修改");
    }

    public void login(String username,String password){
        System.out.println("进行数据库对比");
    }


}

         我们在登录时增加权限验证。

$3. 将目标类配置到Spring中。

<bean name="cat" class="com.qcby.service.Cat"/>

$4. 定义切面类

java">public class 权限 {
    public void 验证(){
        System.out.println("进行权限验证");
    }
}

$5. 在配置文件中定义切面类

<bean name="qx" class="com.qcby.service.权限"/>

$6. 在配置文件中完成AOP的配置

<!--pointcut:后边是切入点表达式,作用是知道对对面的那个方法进行增强-->

<aop:config>
        <!--配置切面 = 切入点 + 通知组成-->
        <aop:aspect ref="qx">
            <aop:before method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>
            <!--after:最终通知finally(无论成功或失败都会执行)-->
<!--            <aop:after method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>-->
<!--            <aop:after-returning method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>-->
<!--            <aop:after-throwing method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>-->

<!--                <aop:around method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>-->
        </aop:aspect>
    </aop:config>

$7. 测试test

java">public class Test2 {
    @Test
    public void test(){
        ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
        Cat cat=(Cat) ac.getBean("cat");
        cat.login("小猫","1245");
    }
}


3.4 切入点的表达式

再配置切入点的时候,需要定义表达式,具体展开如下:

        切入点表达式的格式如下:

                execution([修饰符] [返回值类型] [类全路径] [方法名 ( [参数] )])

 其中,

        修饰符可以省略不写,不是必须要出现的。

        返回值类型是不能省略不写的,根据你的方法来编写返回值,可以使用 * 代替。

包名,类名,方法名,参数的规则如下:

例如

        com.qcby.demo3.BookDaoImpl.save()

1. 首先包名,类名,方法名是不能省略不写的,但是可以使用 * 代替

2. 中间的包名可以使用 * 号代替

3. 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl

4. 方法也可以使用 * 号代替

5. 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..

比较通用的表达式

                execution(* com.qcby.*.ServiceImpl.save(..))

举例2

        com.qcby.demo3.BookDaoImpl当中所有的方法进行增强

                        execution(* com.qcby.*.ServiceImpl.*(..))

举例3

        com.qcby.demo3包当中所有的方法进行增强

                        execution(* com.qcby.*.*.*(..))


 3.5 AOP的通知类型

1. 前置通知

目标方法执行前,进行增强。

        如上配置案例就是前置通知。

2. 环绕通知

目标方法执行前后,都可以进行增强。

目标对象的方法需要手动执行。

java">// 环绕通知
public void 验证(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    System.out.println("before.............");
    //  执行被增强的方法
    proceedingJoinPoint.proceed();
    
    System.out.println("after.............");
}

xml配置

<aop:around method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>

3. 最终通知

目标方法执行成功或者失败,进行增强。

java">public class Cat {


    public void add(int nums){
        System.out.println("添加了"+nums);
    }

    public void delete(int nums){
        System.out.println("删除了"+nums);
    }
    public void update(){
        System.out.println("进行了修改");
    }

    public void login(String username,String password){
        int a=10/0;
        System.out.println("进行数据库对比");
    }


}
java">public class 权限 {
    public void 验证(){
        System.out.println("进行权限验证");
    }
}

xml配置

<aop:after method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>

测试:         

        切入点有错误还是进行了增强。 

4.  后置通知

目标方法执行成功后,进行增强。

目标文件配置

java">public void login(String username,String password){
        int a=10/0;
        System.out.println("进行数据库对比");
    }

xml配置

<aop:after-returning method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>

目标方法有错误,不进行增强。 

改正后: 

java"> public void login(String username,String password){
//        int a=10/0;
        System.out.println("进行数据库对比");
    }

可以进行增强。

5. 异常通知

目标方法执行失败后,进行增强。(发生异常的时候才会执行,否则不执行)

目标文件

java">public void login(String username,String password){
        int a=10/0;
        System.out.println("进行数据库对比");
    }

xml配置: 

<aop:after-throwing method="验证" pointcut="execution(public void com.qcby.service.Cat.login(..))"/>

测试

若目标文件改正确之后,

不进行增强


 4. Spring的AOP技术-注解方式

4.1. AOP注解方式入门程序

创建maven工程,导入坐标。编写接口,完成IOC的操作。步骤略。

编写切面类

给切面类添加注解 @Aspect,编写增强的方法,使用通知类型注解声明。

1. 配置xml扫描注解

<!--开启注解扫描-->
    <context:component-scan base-package="com.qcby"></context:component-scan>

2. 配置注解 

给切面类添加注解 @Aspect,编写增强的方法,使用通知类型注解声明

java">@Component
@Aspect  //生成代理对象
public class 权限 {
    public void 验证(){
        System.out.println("进行权限验证");
    }
}
java">@Component
public class Cat {


    public void add(int nums){
        System.out.println("添加了"+nums);
    }

    public void delete(int nums){
        System.out.println("删除了"+nums);
    }
    public void update(){
        System.out.println("进行了修改");
    }

    public void login(String username,String password){
//        int a=10/0;
        System.out.println("进行数据库对比");
    }


}

3. 配置文件中开启自动代理

<!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

4. 通知类型注解

@Before -- 前置通知

@AfterReturing -- 后置通知

@Around -- 环绕通知(目标对象方法默认不执行的,需要手动执行)

@After -- 最终通知

@AfterThrowing -- 异常抛出通知

 @Before -- 前置通知

java">@Before(value = "execution(public void com.qcby.service.Cat.login(..))")
    public void before(){
        System.out.println("before.............");

    }

 @AfterReturing -- 后置通知

java">@AfterReturning(value = "execution(public void com.qcby.service.Cat.login(..))")
    public void 验证(){
        System.out.println("before.............");

    }

@Around -- 环绕通知(目标对象方法默认不执行的,需要手动执行) 

java">@Around(value = "execution(public void com.qcby.service.Cat.login(..))")
    public void before(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("before.............");
        //  执行被增强的方法
        proceedingJoinPoint.proceed();
        System.out.println("after.............");
    }

@After -- 最终通知 

java">@After(value = "execution(public void com.qcby.service.Cat.login(..))")
    public void 验证(){
        System.out.println("before.............");

    }

@AfterThrowing -- 异常抛出通知 

java">@AfterThrowing(value = "execution(public void com.qcby.service.Cat.login(..))")
    public void 验证(){
        System.out.println("before.............");

    }


http://www.niftyadmin.cn/n/5796996.html

相关文章

【CSS in Depth 2 精译_088】第五部分:添加动效概述 + 第 15 章:CSS 过渡特效概述 + 15.1:状态间的由此及彼

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 15 章 过渡】 ✔️ 15.1 状态间的由此及彼 ✔️15.2 定时函数 文章目录 第 5 部分 添加动效 Adding motion第 15 章 过渡 Transitions15.1 状态间的由此及彼 From here…

宝塔面板跨服务器数据同步教程:双机备份零停机

之前发布的教程不够完美&#xff0c;安全性也不够&#xff0c;所以优化了很多地方 ┌────────────────────────────────────────┐ │ 系统功能选项 │ ├─────────────────────────…

如何在centos系统上挂载U盘

在CentOS上挂载NTFS格式的U盘,需要执行一系列步骤,包括识别U盘设备、安装必要的软件、创建挂载点,并最终挂载U盘。以下是在CentOS上挂载NTFS格式U盘的详细步骤: 一、准备工作 确认CentOS版本: 确保你的CentOS系统已经安装并正常运行。不同版本的CentOS在命令和工具方面可能…

架构师应如何考虑重构

目录 重构的目的、时机、难点 1.1重构的目的 1.2何时重构 1.2.1 添加新功能的时候对周边历史进行小型重构 1.2.2 cide review 时 1.2.3 有计划有目的的重构 1.2.5 何时不该重构 1.3、重构的难点 1.3.1 保证重构前后行为一致。 1.3.2 减少出现问题带来的影响 1.4 常见的重构…

SpringBoot3+Vue3开发在线考试系统

项目介绍 项目分为3种角色&#xff0c;分别为&#xff1a;超级管理员、老师、学生。超级管理员&#xff0c;负责系统的设置、角色的创建、菜单的管理、老师的管理等功能&#xff0c;也可以叫做系统管理员&#xff1b;老师角色&#xff0c;负责系统业务的管理&#xff0c;包括学…

安全算法基础(一)

安全算法是算法的分支之一&#xff0c;还的依靠大量的数学基础进行计算&#xff0c;本文参照兜哥的AI安全样本对抗&#xff0c;做一个简单的算法安全概括&#xff0c;从零学习。 最新的安全算法对于我们常规的攻击样本检测&#xff0c;效果是不理想的&#xff0c;为了探究其原…

如何正确计算显示器带宽需求

1. 对显示器的基本认识 一个显示器的参数主要有这些&#xff1a; 分辨率&#xff1a;显示器屏幕上像素点的总数&#xff0c;通常用横向像素和纵向像素的数量来表示&#xff0c;比如19201080&#xff08;即1080p&#xff09;。 刷新率&#xff1a;显示器每秒钟画面更新的次数&…

upload-labs-master第21关超详细教程

目录 环境配置解题思路利用漏洞 操作演示 环境配置 需要的东西 phpstudy-2018 链接&#xff1a; phpstudy-2018 提取码&#xff1a;0278 32 位 vc 9 和 11 运行库 链接&#xff1a; 运行库 提取码&#xff1a;0278 upload-labs-master 靶场 链接&#xff1a; upload-lasb-ma…