当前位置: 首页 > news >正文

SSM基础专项复习6——Spring框架AOP(3)

系列文章

1、SSM基础专项复习1——SSM项目整合-CSDN博客

2、SSM基础专项复习2——Spring 框架(1)-CSDN博客

3、SSM基础专项复习3——Spring框架(2)-CSDN博客

4、SSM基础专项复习4——Maven项目管理工具(1)-CSDN博客

文章目录

系列文章

1、AOP 

1.1 什么是AOP

1.2 . AOP 的优势

1.3. AOP 的底层原理

2、Spring 的AOP技术-配置文件方式

2.1 AOP 相关的术语

2.2 AOP 配置文件方式的入门

2.3 . 切入点的表达式

2.4  AOP 的通知类型

3、Spring 的AOP技术-注解方式

3.1 入门程序

3.2 纯注解的方式


1、AOP 

1.1 什么是AOP

什么是 AOP 的技术?

  • 在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程。
  • AOP 是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。
  • AOP 最早由 AOP 联盟的组织提出的,制定了一套规范,Spring 将AOP 思想引入到框架中,必须遵守 AOP 联盟的规范
  • 通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术
  • AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring 框架中的一个重要内容,是函数式编程的一种衍生范型
  • 利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)。可以在不修改源代码的前提下,对程序进行增强

1.2 . AOP 的优势

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

1. 减少重复的代码

2. 提供开发的效率

3. 维护方便

1.3. AOP 的底层原理

JDK 的动态代理技术

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

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

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

cglib 代理技术

2、Spring 的AOP技术-配置文件方式

2.1 AOP 相关的术语

Joinpoint(连接点) 所谓连接点是指那些被拦截到的点。在spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点

Pointcut(切入点) -- 所谓切入点是指我们要对哪些

Joinpoint 进行拦截的定义

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

Target(目标对象)-- 代理的目标对象 Weaving(织入)-- 是指把增强应用到目标对象来创建新的代理对象的过程

Proxy(代理)-- 一个类被 AOP 织入增强后,就产生一个结果代理类

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

2.2 AOP 配置文件方式的入门

创建 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>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</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>

编写具体的接口和实现类

package com.qcby.service;

public interface UserService {
    public void save();
}
package com.qcby.service;

public class UserServiceImpl implements UserService {
//连接点,切入点
    @Override
    public void save() {
        System.out.println("业务层:保存用户...");
    }
}

将目标类配置到 Spring 中

<bean id="userService" class="com.qcby.service.UserServiceImpl"/>

定义切面类

package com.qcby.aspect;
/**
 * 自定义切面类 = 切入点(表达式) + 通知(增强的代码)
 */
public class MyXmlAspect {
    /**
     * 通知
     */
    public void log(){
    // 发送手机短信
    // 发送邮件/记录日志/事务管理
        System.out.println("增强的方法执行了...");
    }
}

在配置文件中定义切面类

<bean id="myXmlAspect" class="com.qcby.aspect.MyXmlAspect"/>

在配置文件中完成 aop 的配置

<!--配置 AOP 的增强-->
    <aop:config>
        <!--配置切面 = 切入点 + 通知组成-->
        <aop:aspect ref="myXmlAspect">
            <!--前置通知:UserServiceImpl 的 save 方法执行前,会增强-->
            <aop:before method="log" pointcut="execution(public void com.qcby.service.UserServiceImpl.save())" />
        </aop:aspect>
    </aop:config>

完成测试

import com.qcby.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class TestDemo {
    @Autowired
    private UserService userService;
    /**
     * 测试
     */
    @Test
    public void run1(){
        userService.save();
    }
}

测试结果

2.3 . 切入点的表达式

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/springcontext.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--管理 bean 对象-->
<bean id="userService" class="com.qcbyjy.demo2.UserServiceImpl"/><!--配置切面类,把该类交给 IOC 容器管理-->
<bean id="myXmlAspect" class="com.qcbyjy.demo2.MyXmlAspect"/>
<!--配置 AOP 的增强-->
<aop:config>
<!--配置切面 = 切入点 + 通知组成-->
<aop:aspect ref="myXmlAspect">
<!--前置通知:UserServiceImpl 的 save 方法执行前,会增强<aop:before method="log" pointcut="execution(publicvoid com.qcbyjy.demo2.UserServiceImpl.save())" />
-->
<!--切入点的表达式
execution() 固定的写法
public 是可以省略不写的方法的返回值 int String 通用的写法,可以编写*不能省略不写的
包名+类名 不能省略不写的,编写*
UserServiceImpl AccountServiceImpl
方法名称 save() 可以写 *
参数列表 (..) 表示任意类型和个数的参数比较通用的表达式:execution(public *
com.qcbyjy.*.*ServiceImpl.*(..))
-->
<aop:before method="log" pointcut="execution(*com.qcby.*.*ServiceImpl.save*(..))" />
</aop:aspect>
</aop:config>
</beans>

  <aop:before method="验证"

                      pointcut="execution(public void com.qcby.service.Cat.login(..))"/>

在这条语句中,before为通知的类型。pointcut后为目标类的方法路径,当方法需要传参时用“..”代替。

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

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

修饰符可以省略不写,不是必须要出现的。返回值类型是不能省略不写的,根据你的方法来编写返回值,可以使用 * 代替。

2.4  AOP 的通知类型

1. 前置通知 目标方法执行前,进行增强。

2. 最终通知 目标方法执行成功或者失败,进行增强。

3. 后置通知 目标方法执行成功后,进行增强。

4. 异常通知 目标方法执行失败后,进行增强。

5. 环绕通知 目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。

切面类

    public Object log4(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("(环绕通知)目标方法执行前的增强逻辑");

        // 手动执行目标对象的方法
        Object result = joinPoint.proceed();

        System.out.println("(环绕通知)目标方法执行后的增强逻辑");

        return result;
    }
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/springcontext.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--管理 bean 对象-->
<bean id="userService" class="com.qcbyjy.demo2.UserServiceImpl"/><!--配置切面类,把该类交给 IOC 容器管理-->
<bean id="myXmlAspect" class="com.qcbyjy.demo2.MyXmlAspect"/><!--配置 AOP 的增强-->
<aop:config>
<!--配置切面 = 切入点 + 通知组成-->
<aop:aspect ref="myXmlAspect">
<!--
AOP 的通知类型
前置通知:目标方法执行前,进行增强。<aop:before method="log" pointcut="execution(*com.qcbyjy.*.*ServiceImpl.save*(..))" />
最终通知:目标方法执行成功或者失败,进行增强。<aop:after method="log" pointcut="execution(*com.qcbyjy.*.*ServiceImpl.save*(..))" />
后置通知:目标方法执行成功后,进行增强。<aop:after-returning method="log"
pointcut="execution(* com.qcbyjy.*.*ServiceImpl.save*(..))" />
异常通知:目标方法执行失败后,进行增强。<aop:after-throwing method="log"
pointcut="execution(* com.qcbyjy.*.*ServiceImpl.save*(..))" />
环绕通知:目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。
-->
<aop:around method="aroundLog" pointcut="execution(*
com.qcbyjy.*.*ServiceImpl.save*(..))" />
</aop:aspect>

完整流程如下: 

3、Spring 的AOP技术-注解方式

3.1 入门程序

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

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

@Component // 把该类交给 IOC 去管理
@Aspect // 声明是切面类 == <aop:aspect ref="myXmlAspect">
public class MyXmlAspect {
    /**
     * 通知
     */
    @Before(value = "execution(public * com.qcby.*.*ServiceImpl.save(..))")
    public void log1(){
    // 发送手机短信
    // 发送邮件/记录日志/事务管理
        System.out.println("(前置通知)增强的方法执行了...");
    }
}

配置注解(开启自动代理)

<aop:aspectj-autoproxy/>

@Component设置bean

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class Demo3 {
@Autowired
private OrderService orderService;
/**
* 测试
*/
@Test
public void run1(){
orderService.save();
}
}

3.2 纯注解的方式

package com.qcbyjy.demo3;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration // 配置类
@ComponentScan(value = "com.qcbyjy.demo3") // 扫描包@EnableAspectJAutoProxy // 开启自动代理 == <aop:aspectj-autoproxy/>
public class SpringConfig {
}

相关文章:

  • Appium高级操作--ActionChains类、Toast元素识别、Hybrid App操作、手机系统API的操作
  • 【前端动态列表渲染:如何正确管理唯一标识符(Key)?】
  • 前端面试:axios 是否可以取消请求?
  • Linux下部署前后端分离项目
  • Java Class类文件结构
  • 如何在 PostgreSQL 中运行 TLS 回归测试
  • 电子电气架构 --- 智能电动汽车的品牌竞争转变
  • JVM之Arthas的jvm命令
  • OpenCV(应用) —— 凸包检测的实战应用
  • 新鲜速递:OpenAI-Agents-Python:构建智能代理系统的轻量级框架
  • Blueprint —— 蓝图的使用
  • c++之STL库
  • .net 6程序在IIS中部署后点击IIS设置报错“执行此操作时出错”
  • 优化用户体验:关键 Web 性能指标的获取、分析、优化方法
  • Vue项目搜索引擎优化(SEO)终极指南:从原理到实战
  • SpringBoot第二天
  • 基于Spring Boot的网上宠物店系统的设计与实现(LW+源码+讲解)
  • 已知含税金额和税率求不含税金额
  • 【 <一> 炼丹初探:JavaWeb 的起源与基础】之 JavaWeb 中的文件上传与下载:实现文件管理功能
  • 归并排序的一些介绍
  • 百岁太极拳大师、陈氏太极拳第十一代嫡宗传人陈全忠逝世
  • 他比李白接地气,比杜甫乐观,比白居易刚毅
  • 经济日报:上海车展展现独特魅力
  • 解码人格拼图:探索心理健康的多维视角
  • 安徽一交通事故责任认定引质疑:民警和司法鉴定人被处罚,已中止诉讼
  • 王宝强谈《棋士》:饰演这个灰度人物有一种被割裂的痛苦