Spring 用法学习总结(三)之 AOP

Spring学习

  • 7 bean的生命周期
  • 8 AOP面向切面编程
    • 8.1 AOP相关术语
    • 8.2 AOP使用


7 bean的生命周期

bean的生命周期主要为bean实例化、bean属性赋值、bean初始化、销毁bean,其中在实例化和初始化前后都使用后置处理器方法,而InstantiationAwareBeanPostProcessor 继承了BeanPostProcessor
可以看下这篇博客大致了解一下:
一文读懂 Spring Bean 的生命周期
在这里插入图片描述
bean的作用域

  • 单例(Singleton):在整个应用中,只创建bean的一个实例
  • 原型(Prototype):每次注入或者通过Spring的应用上下文获取的时候,都会创建一个新的bean实例
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例

8 AOP面向切面编程

AOP(Aspect Oriented Programming)面向切面编程,利用 AOP 可以使得业务模块只需要关注核心业务的处理,不用关心其他的(如安全管理)。可以不通过修改源代码的方式,在主干功能里面添加新功能。

使用AOP相关的包:百度网盘
在这里插入图片描述

8.1 AOP相关术语

通知(Advice)
通知定义了何时使用切面,有以下五种类型的通知

  • 前置通知(Before):在目标方法被调用之前调用通知功能
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
  • 返回通知(After-returning):在目标方法成功执行之后调用通知
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

连接点(Join point)

连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点(Pointcut)

切点定义了何处使用切面。会匹配通知(Advice)所要织入的一个或多个连接点。我们通常使用
明确的类和方法名称,或利用正则表达式定义所匹配的类和方法名称来指定这些切点。

切面(Aspect)

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

引入(Introduction)

引入允许我们向现有的类添加新方法或属性。

目标对象(Target)

Target是织入 Advice 的目标对象

织入(Weaving)

织入就是把通知(Advice)添加到目标对象具体的连接点上的过程

在这里插入图片描述

8.2 AOP使用

切入点表达式语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) ),此外还可以对切入点进行限制,因为“&”在XML中有特殊含义,所以在Spring的XML配置里面描述切点时,我们可以使用and来代替“&&”。同样,or和not可以分别用来代替“||”和“!”

在这里插入图片描述
在这里插入图片描述

基于注解

创建配置类ConfigAop

package springstudy2;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

//创建ConfigAop配置类
@Configuration //@Configuration标记类作为配置类替换xml配置文件
@EnableAspectJAutoProxy(proxyTargetClass = true) //启用自动代理
@ComponentScan(basePackages = {"springstudy2"}) //开启注解扫描
public class ConfigAop {
}

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages = {“springstudy2”})

三个注解相当于以下代码

<?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:jdbc="http://www.springframework.org/schema/jdbc"  
	   xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
       http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false">

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

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

创建User类

package springstudy2;

import org.springframework.stereotype.Component;


//创建User对象
@Component
public class User {
    public void add() {
        //int a = 10 / 0;
        System.out.println("调用add方法...");
    }

    public void test() {
        System.out.println("调用test方法...");
    }
}

创建代理 UserProxy

如果有多个代理,可以通过@Order注解指定优先级,数字越小,优先级越高

package springstudy2;

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

//创建UserProxy对象
//增强的类
@Component
@Aspect //生成代理对象
@Order(1)//代理优先级,数字越小,优先级越高
public class UserProxy {

    //相同切入点抽取
    @Pointcut(value = "execution(* springstudy2.User.add(..))")
    public void pointdemo() { //pointdemo()方法的内容并不重要,在这里它实际上应该是空的
    }


    //前置通知
    //@Before 注解表示作为前置通知
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("在目标方法被调用之前调用通知功能.........");
    }
    @Before(value = "execution(* springstudy2.User.test(..))")
    public void before1() {
        System.out.println("test 在目标方法被调用之前调用通知功能.........");
    }
    //后置通知
    @After(value = "execution(* springstudy2.User.add(..))")
    public void after() {
        System.out.println("在目标方法完成之后调用通知.........");
    }
    //返回通知
    @AfterReturning(value = "pointdemo()")
    public void afterReturning() {
        System.out.println("在目标方法成功执行之后调用通知.........");
    }
    //异常通知
    @AfterThrowing(value = "execution(* springstudy2.User.add(..))")
    public void afterThrowing() {
        System.out.println("在目标方法抛出异常后调用通知.........");
    }
    //环绕通知
    @Around(value = "execution(* springstudy2.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前,在被通知的方法调用之前.........");
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后,在被通知的方法调用之后.........");
    }
}

上述代码中,@afterReturning 和 @after 注解的执行顺序存在版本问题(有争议),据说从Spirng 5.2.7那一版开始,通知注解的执行顺序如下(不知道后面改没改。。。我的Spring5.3.9是这样):

  1. @Around注解方法的前半部分业务逻辑
  2. @Before注解方法的业务逻辑
  3. 目标方法的业务逻辑
  4. @AfterThrowing(若目标方法有异常,执行@AfterThrowing注解方法的业务逻辑)
  5. @AfterReturning(若目标方法无异常,执行@AfterReturning注解方法的业务逻辑)
  6. @After(不管目标方法有无异常,都会执行@After注解方法的业务逻辑)
  7. @Around注解方法的后半部分业务逻辑(@Around注解方法内的业务逻辑若对ProceedingJoinPoint.proceed()方法没做捕获异常处理,直接向上抛出异常,则不会执行Around注解方法的后半部分业务逻辑;若做了异常捕获处理,则会执行)

创建 PersonProxy 代理

package springstudy2;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//创建PersonProxy对象
//增强的类
@Component
@Aspect //生成代理对象
@Order(2)//代理优先级,数字越小,优先级越高
public class PersonProxy {
    @Before(value = "execution(* springstudy2.User.add(..))")
    public void before() {
        System.out.println("person 在目标方法被调用之前调用通知功能.........");
    }
}

测试类Test

package springstudy2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);//ConfigAop为配置类
        User user = context.getBean("user", User.class);
        user.add();
        user.test();
    }
}

执行结果
在这里插入图片描述

基于XML

在src目录下创建bean3.xml文件

<?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/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--创建对象-->
    <bean id="user" class="springstudy2.User"></bean>
    <bean id="userproxy" class="springstudy2.UserProxy"></bean>
    <bean id="personproxy" class="springstudy2.PersonProxy"></bean>

    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* springstudy2.User.add(..))"/>
        <!--配置切面-->
        <aop:aspect ref="userproxy" order="1"> <!--通过 orde r确定优先级-->
            <!--增强作用在具体的方法上-->
            <!--method="before"中 before 是UserProxy类中的方法名-->
            <aop:before method="before" pointcut-ref="p"/>
            <aop:before method="before" pointcut="execution(* springstudy2.User.test(..))"/>
            <aop:after method="after" pointcut-ref="p"/>
            <aop:after-returning method="afterReturning" pointcut-ref="p"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="p"/>
            <aop:around method="around" pointcut-ref="p"/>
        </aop:aspect>
        <aop:aspect ref="personproxy" order="2">
            <!--增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
</beans>

修改Test类

package springstudy2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
        User user = context.getBean("user", User.class);
        user.add();
        user.test();
    }
}

基于XML的AOP执行结果
在这里插入图片描述
基于注解的AOP执行结果
在这里插入图片描述

注:与注解执行顺序不一致,原因是两者使用的AOP代理不同,在基于注解的AOP中,通知的执行顺序是确定的,而多个切面执行顺序由@Order注解来控制,当没有指定@Order注解时,Spring会按照切面类的类名进行排序,从字母顺序最小的切面开始执行,依次递增;在XML配置中,@around注解声明在@before注解前面,则@around注解先执行,否则,@before注解先执行

<aop:after method="after" pointcut-ref="p"/>
<aop:after-returning method="afterReturning" pointcut-ref="p"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="p"/>
<aop:around method="around" pointcut-ref="p"/>
<aop:before method="before" pointcut-ref="p"/>
<aop:before method="before" pointcut="execution(* springstudy2.User.test(..))"/>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/387662.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux之多线程

目录 一、进程与线程 1.1 进程的概念 1.2 线程的概念 1.3 线程的优点 1.4 线程的缺点 1.5 线程异常 1.6 线程用途 二、线程控制 2.1 POSIX线程库 2.2 创建一个新的线程 2.3 线程ID及进程地址空间布局 2.4 线程终止 2.5 线程等待 2.6 线程分离 一、进程与线程 在…

HDFS的超级用户

一. 解释原因 HDFS(Hadoop Distributed File System)和linux文件系统管理一样&#xff0c;也是存在权限控制的。 但是很不一样的是&#xff0c; 在Linux文件系统中&#xff0c;超级用户Superuser是root而在HDFS中&#xff0c;超级用户Superuser是启动了namenode的用户&#x…

4核16g配置咋样?还不错,阿里云4核16G服务器26元1个月

4核16g配置咋样&#xff1f;还不错&#xff0c;阿里云4核16G服务器26元1个月&#xff0c;阿里云4核16G服务器配置优惠价格ECS云服务器经济型e实例26元1个月、149元半年、79元3个月&#xff0c;4核16G通用算力u1服务器、通用型g7、通用型g8i、AMD通用型g8a、性能增强通用型g8ae、…

html从零开始6:关系选择器、css盒子模型、弹性盒子模型【搬代码】

关系选择器 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width,…

Linux日志管理服务 rsyslogd

文章目录 1. 基本介绍2. 系统常用的日志3. 日志管理服务 rsyslogd 1. 基本介绍 日志文件是重要的系统信息文件&#xff0c;其中记录了许多重要的系统事件&#xff0c;包括用户的登录信息、系统的启动信息、系统的安全信息、邮件相关信息、各种服务相关信息等。日志对于安全来说…

QQ群微信群强制加群/随机小姐姐视频分享打赏裂变PHP源码

很多人再找qq群或者微信分享小姐姐视频打赏的裂变源码&#xff0c;这次就分享出来&#xff01; 下载地址QQ群微信群强制加群.zip官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘

中国电子学会2023年12月份青少年软件编程Scratch图形化等级考试试卷二级真题(含答案)

2023-12 Scratch二级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1.在制作推箱子游戏时&#xff0c;地图是用数字形式储存在电脑里的&#xff0c;下图是一个推箱子地图&#xff0c;地图表示如下&#x…

QGIS教程 加载shape数据 矢量数据(批量)

一. 前言 本篇文章主要介绍QGIS的使用&#xff0c;包括如何加载矢量shape数据、查看数据属性、如何加载txt属性数据、怎么用脚本批量加载矢量数据等内容。 如果想了解QGIS&#xff0c;可以参考博文&#xff1a; QGIS基本介绍 如果想了解shape数据格式详情&#xff0c;可以参考…

bpmn-js 事件总线处理

bpmn-js中使用EventBus作为事件的处理句柄&#xff0c;EventBus的使用和我们常规使用的事件总线没啥大的区别&#xff0c;其源码位于&#xff1a;/diagram-js/lib/core/EventBus.js &#xff08;bpmn-js使用diagram-js实现流程图的web端绘制呈现工具&#xff09;。 EventBus使用…

权限提升:利用Linux错配提权

目录 Linux权限基础 Linux用户权限 Linux文件权限 特殊的Linux文件权限 Linux本机信息收集 Linux错配提权 crontab计划任务提权 SUID提权 Linux权限基础 Linux用户权限 在Linux中&#xff0c;根据权限的不同&#xff0c;大致可以分为三种&#xff1a;超级用户&#x…

steam游戏搬砖项目靠谱吗?有没有风险?

作为一款fps射击游戏&#xff0c;csgo在近几年可谓是火出圈&#xff0c;作为一款全球竞技游戏&#xff0c;深受玩家喜爱追捧&#xff0c;玩家追求的就是公平公正&#xff0c;各凭本事&#xff0c;像其他游戏可能还会有皮肤等装备属性加成&#xff0c;在csgo里面是不存在的。 纯…

【Java程序设计】【C00257】基于Springboot的校园二手书交易平台(有论文)

基于Springboot的校园二手书交易平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的乐校园二手书交易管理系统 本系统分为系统功能模块、管理员功能模块、卖家用户功能模块以及用户功能模块。 系统功能模块&…

semantic-kernel 国内代理的配置(详细教程)

1. semantic-kernel概述 Semantic Kernel 是微软提供的一个工具,旨在帮助开发者快速、轻松地将最新的大型语言模型(LLM)技术集成到应用程序中。这意味着通过使用Semantic Kernel,开发者可以在他们的应用中加入先进的人工智能和自然语言理解能力,从而增强应用的功能性。 …

在python中JSON数据格式的使用

什么是JSON&#xff1f; JSON是一种数据格式&#xff0c;由美国程序设计师DouglasCrockford创建的&#xff0c;JSON全名是JavaScript Object Notation,由JSON英文全文字义我们可以推敲JSON的缘由&#xff0c;最初是为JavaScript开发的。这种数据格式由于简单好用被大量应用在We…

Linux第57步_“linux系统镜像”和“根文件系统”重新打包小结

实时总结是很重要的&#xff0c;时间久了&#xff0c;可能会遗忘。下面是“linux系统镜像”和“根文件系统”重新打包小结。 1、linux系统镜像重新打包 在第1次完成linux系统镜像打包后&#xff0c;再重新打包就很容易了 将“bootfs”重新打包 准备打包文件: 输入“cd /ho…

顺序表、链表(ArrayList、LinkedList)

目录 前言&#xff1a; 顺序表&#xff08;ArrayList&#xff09;&#xff1a; 顺序表的原理&#xff1a; ArrayList源码&#xff1a; 的含义&#xff1a;​编辑 ArrayList的相关方法&#xff1a;​编辑 向上转型List&#xff1a; 练习题&#xff08;杨辉三角&#x…

数模.传染病模型plus

一、SIS模型 二、SIR模型 三、SIRS模型 四、SEIR模型

C++类和对象-C++运算符重载->加号运算符重载、左移运算符重载、递增运算符重载、赋值运算符重载、关系运算符重载、函数调用运算符重载

#include<iostream> using namespace std; //加号运算符重载 class Person { public: Person() {}; Person(int a, int b) { this->m_A a; this->m_B b; } //1.成员函数实现 号运算符重载 Person operator(const Per…

【有哪些值得计算机专业学生加入的国企?】

&#x1f680; 编辑&#xff1a;“码上有前” &#x1f680;作者丨重庆搬砖喵知乎 &#x1f680; 文章简介 &#xff1a;计算机专业未来出路 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; &#x1f680;来源&#xff1a;https://www.zhihu.com/qu…

PHP+vue+mysql校园学生社团管理系统574cc

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 前台功能&#xff1a; 首页&#xff1a;展示社团信息和活动…