springAop原理分析-动态代理对象创建过程分析

news2024/11/30 6:57:50

概念

AspectJ

  1. Aspect 切面(由多个切点组成,多个点组成面)

启用@AspectJ支持后,Spring 会自动检测出在应用程序上下文中定义的任何 Bean,如下使用@Aspect 定义的一个切面示例。

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class NotVeryUsefulAspect {

}
  1. Pointcut 切点(被切入的方法)

切入点决定了连接兴趣点,从而使我们能够控制建议的运行时间。Spring AOP 仅支持 Spring bean 的方法执行连接点,因此您可以将切入点视为与Spring bean 上的方法执行相匹配。切入点声明由两部分组成:一个由名称和任何参数组成的签名,以及一个切入点表达式,该表达式准确确定我们感兴趣的方法执行。在 AOP 的@AspectJ注释样式中,切入点签名由常规方法定义提供,切入点表达式通过使用注释进行指示(用作切入点签名的方法必须具有返回类型)。@Pointcut``void

一个示例可能有助于明确切入点签名和切入点表达式之间的区别。下面的示例定义了一个名为 的切入点,该切入点与任何名为 的方法来执行相匹配:anyOldTransfer``transfer

支持的切入点指示符

弹簧 AOP 支持以下 AspectJ 切入点指示符 (PCD), 用于切入点表达式:

  • execution:用于匹配方法执行连接点。这是使用弹簧 AOP 时要使用的主要切入点指示符。
  • within:限制匹配以连接特定类型中的点(使用Spring AOP时执行在匹配类型中声明的方法)。
  • this:限制与连接点的匹配(使用弹簧 AOP 时的方法的执行),其中 Bean 引用(弹簧 AOP 代理)是给定类型的实例。
  • target:限制与连接点的匹配(使用Spring AOP时的方法执行),其中目标对象(正在代理的应用程序对象)是给定类型的实例。
  • args:限制匹配以连接点(使用Spring AOP时执行方法),其中参数是给定类型的实例。
  • @target:限制与连接点(使用Spring AOP时执行方法)的匹配,其中执行对象的类具有给定类型的注释。
  • @args:限制与连接点的匹配(使用Spring AOP时的方法执行),其中传递的实际参数的运行时类型具有给定类型的注释。
  • @within:限制在具有给定注释的类型中连接点的匹配(使用Spring AOP时,执行具有给定注释的类型中声明的方法)。
  • @annotation:将匹配限制为连接点的主题(在 Spring AOP 中运行的方法)具有给定注释的连接点。
  1. Advice 通知(切入的时机,被切入的业务逻辑)

  2. Before 方法执行之前

  3. After方法执行之后

    1. AfterThrowing 方法执行之后异常处理
    2. AfterReturning 方法执行之后,返回结果
  4. Around 环绕通知,方法执行前和执行之后

  5. JoinPoint 连接点,用于获取方法的参数(配合Advice 里的具体通知使用)

    任何建议方法都可以将 类型的参数声明为其第一个参数。请注意,在建议周围需要声明类型的第一个参数,它是 的子类org.aspectj.lang.JoinPointProceedingJoinPointJoinPoint。

    • getArgs():返回方法参数。
    • getThis(): 返回代理对象。
    • getTarget(): 返回目标对象。
    • getSignature(): 返回所建议方法的说明。
    • toString(): 打印所建议方法的有用说明。

关于具体的切面,切点,建议,以及链接点请参考下面官方文档和实战部分代码结合理解

核心技术 (spring.io)

AOP动态代理

spring AOP 默认对 AOP 代理使用标准 JDK 动态代理。这使得任何接口(或一组接口)都可以被代理。

这对于代理类,不是必须实现被代理类接口。缺省情况下,如果业务对象没有可以实现的接口,则使用 CGLIB。由于编程到接口而不是类是很好的做法,因此业务类通常实现一个或多个业务接口。在那些(希望是罕见的)情况下,可以强制使用CGLIB,在这些情况下,您需要建议未在接口上声明的方法,或者需要将代理对象作为具体类型传递给方法。

Aop 动态代理工厂类图

image-20220917114946634

Aop 动态代理对象创建过程

IOC部分

这部分只是展示一个正常bean的创建过程(如果启用了切点代理,这部分是一样的)

image-20220917153207204

initalizeBean 方法和applyBeanPostProcessorsAfterInitialization方法是创建aop动态代理的重要方法,下面aop部分主要以后置处理器的方法进行详细剖析。

AOP部分

applyBeanPostProcessorsAfterInitialization(获取所有后置处理器)

image-20220917154812383

annotationAwareAspectJAutoProxyCreator(切面代理后置处理器)

image-20220917155228123

实战

AOP动态动态代理对象

目录结构

image-20220917160012327

配置类

切面类

package com.kang.aop;

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

import java.util.Date;

/**
 * @Description 切面测试
 * @ClassName Aoptest
 * @Author 康世行
 * @Date 10:06 2022/7/29
 * @Version 1.0
 **/
@Aspect
@Component
public class Aoptest {

    @Pointcut("execution(* *(..))")
    private void beforeTest(){}

    @Before("beforeTest()")
    public void testBefore(JoinPoint account){
        Object[] args = account.getArgs();
        for (Object arg : args) {
            System.out.println("方法执行之前参数->"+arg);
        }
    }

    @AfterReturning("beforeTest()")
    public void testAfter(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println("方法执行之后参数->"+arg);
        }
    }

//    @Around("beforeTest()")
//    public Object testAroundTest(ProceedingJoinPoint joinPoint){
//          Object result=null;
//        try {
//            Object[] args = joinPoint.getArgs();
//            for (Object arg : args) {
//                System.out.println("方法执行之前参数:->"+arg);
//            }
//             result= joinPoint.proceed();
//
//        } catch (Throwable e) {
//            throw new RuntimeException(e);
//        }
//        System.out.println("方法执行完毕");
//        return result;
//    }


}

注解容器上下文配置类(用于扫包和开启aop代理注解)

package com.kang.aop.config;

import com.kang.aop.Aoptest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

/**
 * @Description 开启切面配置
 * @ClassName AppConfig
 * @Author 康世行
 * @Date 10:05 2022/7/29
 * @Version 1.0
 **/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan({"com.kang.aop"})
public class AppConfig {
}

JDK

接口

package com.kang.aop.aoptest;

/**
 * @Description 发送消息接口
 * @ClassName SendMessage
 * @Author 康世行
 * @Date 9:39 2022/7/30
 * @Version 1.0
 **/
public interface SendMessage {

    /**
    * @author 康世行
    * @description: 发送消息
    * @date  2022/7/30 9:40
    * @param msg 消息体
    * @return void
    * @Version1.0
    **/
    void sendMessage(String msg);
}

实现类

package com.kang.aop.aoptest;

import org.springframework.stereotype.Service;

/**
 * @Description 发送消息实现类
 * @ClassName SendMessageImpl
 * @Author 康世行
 * @Date 9:40 2022/7/30
 * @Version 1.0
 **/
@Service("sendMessageImpl")
public class SendMessageImpl implements SendMessage {
    @Override
    public void sendMessage(String msg) {
        System.out.println("发送的消息是->"+msg);
    }
}

package com.kang.aop.aoptest;

import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @ClassName temp
 * @Author 康世行
 * @Date 9:46 2022/7/30
 * @Version 1.0
 **/
@Service("temp")
public class temp implements SendMessage{
    @Override
    public void sendMessage(String msg) {
        System.out.println(msg);
    }
}

结果

image-20220917160657785

CGLIB

实现类

package com.kang.aop.aoptest;

import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @ClassName userSavle
 * @Author 康世行
 * @Date 10:12 2022/7/29
 * @Version 1.0
 **/
@Service
public class UserImpl {
    public void save(String msg){
        System.out.println("保存用户信息:"+msg);
    }
    public String print(String msg){
        String result= "userImpl"+msg;
        return result;
    }
}

结果

image-20220917160550865

完整分析-流程图

https://www.processon.com/view/link/63257d13f346fb3377e81de7

ing msg){
System.out.println(“保存用户信息:”+msg);
}
public String print(String msg){
String result= “userImpl”+msg;
return result;
}
}


**结果**

[外链图片转存中...(img-Ywji2EMS-1685082295412)]

# 完整分析-流程图

**https://www.processon.com/view/link/63257d13f346fb3377e81de7**





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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM8、STM8S003F3P6 实现PWM控制电机HAS10227

背景 有个项目需要控制一台风机的转速,使用STM8S003F3P6 输出PWM控制,这里就详细记录一下调试记录 原理图 原理图比较简单,电机接口CN3 电机接口原理图 与MCU管脚连接位置如下图 首先我们要明白电机的原理 电机 简单来说就是 实现电能与…

闲置手机建站 - 安卓Termux+Hexo搭建属于你自己博客网站【cpolar实现公网访问】

文章目录 1. 安装 Hexo2. 安装cpolar内网穿透3. 公网远程访问4. 固定公网地址 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章,在几秒内,即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并…

助力工业物联网,工业大数据之一站制造业务主题划分【十三】

文章目录 01:一站制造业务主题划分02:一站制造业务维度设计03:一站制造业务主题维度矩阵 01:一站制造业务主题划分 目标:掌握一站制造的主题域及主题的划分实施 来源 主题域划分:业务或者部门划分 业务&am…

PHP基于xlswriter支持无限表头层级Excel导出

本章介绍基于PHP扩展xlswriter的Vtiful\Kernel\Excel类可以支持无限层级的复杂表头导出! 废了九牛二虎之力,终于把这个功能类写完了…后续会持续更新优化 准备xlswriter扩展 windows系统: 到PECL网站下载符合自己本地PHP环境的ddl文件下载地…

Java内部类(成员内部类、静态嵌套类、方法内部类、匿名内部类)

文章目录 一、内部类的共性二、为什么需要内部类三、静态内部类(静态嵌套类)四、成员内部类五、局部内部类(方法内部类)六、匿名内部类 Java 类中不仅可以定义变量和方法,还可以定义类,这样定义在类内部的类…

WSL2+windows terminal

WSL2的安装与使用-Windows与Linux双系统的新选择 既要使用Windows系统满足日常生活,协作办公,又要使用Linux系统满足开发工作,双系统来回重启好麻烦,双主机成本高,远程服务器好多限制,WSL也许是更好的解决…

“智慧赋能 强链塑链”——打造电力特色智慧供应链体系

构建业务数智化、资源集约化、运营一体化、发展绿色化的智慧供应链体系,是电力企业实现智慧供应链建设的使命和目标。同时,在国内外双循环、一带一路、建立统一大市场的政策背景推动下,企业经营和居民生活对电力的需求仍然强劲并持续增长&…

Seata AT模式源码解析一(Seata Server端启动流程)

文章目录 启动类 ServerSessionHolder初始化DefaultCoordinator初始化初始化NettyRemotingServer 启动类 Server seata-server的入口类在Server类中,源码如下: public class Server {/*** The entry point of application.** param args the input arg…

Intel Realsense D405 在Ubuntu18.04下使用kalibr标定

目录 一. 在ubuntu下使用kalibr标定realsense_ros的安装总结下面是标定步骤 一. 在ubuntu下使用kalibr标定 在Realsense官网上librealsense现在D405只接受ROS2下的环境(相机确实很新) 在ROS1下我想到了改设备ID号的方式进行标定 这里需要注意libreals…

蓝桥杯并查集总结

本文先是给出三篇并查集原理解释文章链接,又提供了python代码模版;而后给出了一份蓝桥杯并查集的题单,并附有部分题目及其求解思路、代码。 目录部分 并查集原理 python代码 并查集题单 蓝桥幼儿园 题目描述 输入描述 输出描述 输入…

ERP有哪些系统?运用在哪些行业?

国内目前市面上ERP系统五花八门,但能真正快速匹配企业业务,且可以进行快速迭代二次开发的系统并不多见。 所以在选择ERP系统的时候可以参考下面这张表格中的内容: 目前常见的ERP软件大概可以分为三大类: ① 标准ERP应用&#xf…

白银实时价格应该在最适合的地方下注

小时候我们看战争片,总是发现主角们带兵打仗,战无不胜,偶尔有一场大的失利,但是总是能耐化险为夷,逢凶化吉,甚至最后成功反扑、反败为胜。后来小编一琢磨,发现,其实这些将才们打仗&a…

如何使用C++ 在Word文档中创建列表

列表分类是指在Word文档中使用不同格式排序的列表,来帮助我们一目了然地表达出一段文字的主要内容。比如,当我们描述了某个主题的若干点,就可以用列表把它们一一表达出来,而不是写成完整的段落形式。同时,列表也可以帮…

如何查看mysql里面的锁(详细)

通过查询表统计信息查看 information_schema库下相关事务表和锁相关信息表介绍innodb_trx存储了当前正在执行的事务信息trx_id:事务ID。trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。trx…

各位自学网络安全的同学,你们的学习路线真的对吗

最近在知乎上看到很多问题,都是小白想要转行网络安全行业咨询学习路线和学习资料的,作为一个培训机构,学习路线和免费学习资料肯定是很多的。机构里面的不是顶级的黑阔大佬就是正在学习的同学,也用不上这些内容,每天都…

Educational Codeforces Round 139 (Rated for Div. 2)

Educational Codeforces Round 139 (Rated for Div. 2) Problem - 1766E - Codeforces 显然我们可以把0序列的贡献单独算: i*(n-i1) 考虑只存在1,2,3的情况. 首先通过,观察到一个重要性质: 最多只有三种序列. 含有3或纯1或纯2型.纯1或纯2型纯2或纯1型 我们每次添加…

照片资源异地共享 ? tftgallery、xampp、快解析三种工具就能实现!

我的工作中,经常会收到处理各种图片的任务,在处理完图片之后,怎么发送给客户呢?传输的实现,需要一个安全而稳定的环境和即时方便的工具去进行操作与下载。一般情况下,我们大多会选择微信、QQ来作为传输下载…

Seata AT模式源码解析三(AT模式工作机制)

文章目录 代码示例流程源码解析开启全局事务注册分支事务一阶段提交全局事务提交分支事务二阶段提交全局事务回滚分支事务二阶段回滚 代码示例 从一个微服务示例开始,案例采用Seata官方提供的Demo。 用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持&…

五大网络IO模型

网络IO模型 1. IO是什么? I/O(英语:Input/Output),即输入/输出,通常指数据在存储器(内部和外部)或其他周边设备之间的输入和输出,是信息处理系统&#xff0…

Qt编程基础 | 第七章-MVD框架 | 7.1、MVD框架简介

一、MVD框架 1.1、MVC设计模式 MVC是一种与用户界面相关的设计模式,通过使用该设计模式,可以有效的分离数据与用户界面。MVC设计模式包含三个元素:表示数据的模型(Model)、表示用户界面的视图(View&#x…