Spring_AOP的实现机制-动态代理

Spring_AOP的实现机制-动态代理

  • 1 Spring核心之AOP
    • 1.1 AOP的概念
    • 1.2 AOP的相关术语
  • 2 AspectJ 对 AOP 的实现
    • 2.1 AspectJ的通知类型
    • 2.2 AspectJ的切入点表达式
    • 2.3 代码示例
  • 3 静态代理
  • 4 AOP的实现机制-动态代理
    • 4.1 JDK动态代理
    • 4.2 Cglib动态代理
  • 5 静态代理和动态代理的区别
  • 6 两种动态代理方式区别

1 Spring核心之AOP

1.1 AOP的概念

AOP是Aspect-Oriented Programming,即面向切面编程。
AOP的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
开发中:各自做自己擅长的事情,运行的时候将服务性代码织入到核心业务中。
通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。

1.2 AOP的相关术语

Target(目标对象)
要被增强的对象,一般是业务逻辑类的对象。

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

切面(Aspect)
表示增强的功能,就是一些代码完成的某个功能,非业务功能。是切入点和通知的结合。

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

切入点(Pointcut)
切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

Advice(通知/增强)
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执等。通知类型不同,切入时间不同。

Weaving(织入)
是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

2 AspectJ 对 AOP 的实现

2.1 AspectJ的通知类型

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

2.2 AspectJ的切入点表达式

在这里插入图片描述
以上表达式共 4 个部分。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)。
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中就是方法的签名。
示例

execution(* com.kkb.service.*.*(..))
指定切入点为:定义在 service 包里的任意类的任意方法。

execution(* com.kkb.service..*.*(..))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后面必须跟 “*”,表示包、子包下的所有类。

execution(* com.kkb.service.IUserService+.*(..))
指定切入点为:IUserService 若为接口,则为接口中的任意方法及其所有实现类中的任意方法;若为类, 则为该类及其子类中的任意方法。

2.3 代码示例

1 目标类

//目标类
public class SomeServiceImpl{
    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }
}

2 切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码

/**
 * @Aspect : 是aspectj框架中的注解
 *      作用:表示当前类是切面类
 *      切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
 */
@Aspect
public class MyAspect {

    @After(value = "myPointcut()")
    public void myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
    }

    @Before(value = "myPointcut()")
    public void myBefore(){
        System.out.println("执行前置通知,在目标方法执行之前执行");
    }

    /**
     * @Pointcut : 定义和管理切入点,如果项目中有多个切入点表达式是重复的,可以复用
     *
     * 特点:使用@Pointcut定义在方法上面,这个方法的名称就是切入点表达式的别名其它的通知中,value属性就可以使用这个方法名称,代替切入点表达式了
     *              在
     */
    @Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public void myPointcut(){
        //无需代码
    }
}

3 静态代理

/**
 静态代理类优缺点
	 优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
	 缺点:
		 1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
		 2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
 */

1:下面是一个去电影院看电影的例子

public interface Movie {
    //看电影
    void play();
}

2、RealMovie 是实现类

/**
 * 核心业务,只看电影
 */
public class RealMovie implements Movie {
    @Override
    public void play() {
        System.out.println("您正在观看电影 《肖申克的救赎》");
    }
}

3:Cinema是代理类

/**
 * 代理类
 */
public class Cinema implements Movie {

    private RealMovie movie;
    //代理角色,代理
    public Cinema(RealMovie movie) {
        super();
        this.movie = movie;
    }

    @Override
    public void play() {
        guanggao(true);(服务型业务)
        //你看电影(核心业务是看电影)
        movie.play();(服务型业务)
        guanggao(false);
    }
    //中介(电影院)的附属操作
    public void guanggao(boolean isStart){
        if ( isStart ) {
            System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");
        } else {
            System.out.println("电影马上结束了,爆米花、可乐、口香糖8.8折,买回家吃吧!");
        }
    }

}

4:测试类

public class ProxyTest {

    public static void main(String[] args) {
        RealMovie realmovie = new RealMovie();

        //代理,中介还会添加一些附属操作
        Movie movie = new Cinema(realmovie);
        movie.play();
    }
}

5:控制台输出

电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!
您正在观看电影 《肖申克的救赎》
电影马上结束了,爆米花、可乐、口香糖8.8折,买回家吃吧!

4 AOP的实现机制-动态代理

4.1 JDK动态代理

/**
 *  基于接口的动态代理:实现InvocationHandler接口->调用处理程序Proxy->代理
 *
 * 具体步骤是:
 * a. 实现InvocationHandler接口创建自己的调用处理器
 * b. 给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类
 * c. 以调用处理器类型为参数,利用反射机制得到动态代理类的构造函数
 * d. 以调用处理器对象为参数,利用动态代理类的构造函数创建动态代理类对象
 *
 * 好处:一个动态代理类可以代理多个类,只要是实现了同一个接口即可;复用性高
 *
 */

JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。

4.2 Cglib动态代理

Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
DK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。

5 静态代理和动态代理的区别

1 静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
2 静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
3 静态代理,在程序运行前,代理类的.class文件就已经存在了;动态代理,在程序运行时,运用反射机制动态创建而成。

6 两种动态代理方式区别

1 JDK动态代理只能对实现了接口的类生成代理,而不能针对类;Cglib是针 对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final 。
2 Cglib一个目标类方法会生成两个代理方法,一个重写目标方法,并实现代理逻辑,还有一个直接调用目标类方法。

最后,如果有问题,希望指正,一起进步。

热门文章

暂无图片
编程学习 ·

exe4j详细使用教程(附下载安装链接)

一、exe4j介绍 ​ exe4j是一个帮助你集成Java应用程序到Windows操作环境的java可执行文件生成工具,无论这些应用是用于服务器,还是图形用户界面(GUI)或命令行的应用程序。如果你想在任务管理器中及Windows XP分组的用户友好任务栏…
暂无图片
编程学习 ·

AUTOSAR从入门到精通100讲(126)-浅谈车载充电系统通信方案

01 引言 本文深入研究车载充电系统策略,设计出一套基于电动汽车电池管理系统与车载充电机的CAN通信协议,可供电动汽车设计人员参考借鉴。 02 电动汽车充电系统通讯网络 电动汽车整车控制系统中采用的是CAN总线通信方式,由一个整车内部高速CAN网络、内部低速CAN网络和一个充电…
暂无图片
编程学习 ·

CMake(九):生成器表达式

当运行CMake时,开发人员倾向于认为它是一个简单的步骤,需要读取项目的CMakeLists.txt文件,并生成相关的特定于生成器的项目文件集(例如Visual Studio解决方案和项目文件,Xcode项目,Unix Makefiles或Ninja输入文件)。然…
暂无图片
编程学习 ·

47.第十章 网络协议和管理配置 -- 网络配置(八)

4.3.3 route 命令 路由表管理命令 路由表主要构成: Destination: 目标网络ID,表示可以到达的目标网络ID,0.0.0.0/0 表示所有未知网络,又称为默认路由,优先级最低Genmask:目标网络对应的netmaskIface: 到达对应网络,应该从当前主机哪个网卡发送出来Gateway: 到达非直连的网络,…
暂无图片
编程学习 ·

元宇宙技术基础

请看图: 1、通过AR、VR等交互技术提升游戏的沉浸感 回顾游戏的发展历程,沉浸感的提升一直是技术突破的主要方向。从《愤怒的小鸟》到CSGO,游戏建模方式从2D到3D的提升使游戏中的物体呈现立体感。玩家在游戏中可以只有切换视角,进而提升沉浸…
暂无图片
编程学习 ·

flink的伪分布式搭建

一 flink的伪分布式搭建 1.1 执行架构图 1.Flink程序需要提交给 Job Client2.Job Client将作业提交给 Job Manager3.Job Manager负责协调资源分配和作业执行。 资源分配完成后,任务将提交给相应的 Task Manage。4.Task Manager启动一个线程以开始执行。Task Manage…
暂无图片
编程学习 ·

十进制正整数与二进制字符串的转换(C++)

Function one: //十进制数字转成二进制字符串 string Binary(int x) {string s "";while(x){if(x % 2 0) s 0 s;else s 1 s;x / 2;}return s; } Function two: //二进制字符串变为十进制数字 int Decimal(string s) {int num 0, …
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统: 微信小程序——辩论管理前台涉及技术:WXML 和 WXS…
暂无图片
编程学习 ·

树莓派驱动DHT11温湿度传感器

1,直接使用python库 代码如下 import RPi.GPIO as GPIO import dht11 import time import datetimeGPIO.setwarnings(True) GPIO.setmode(GPIO.BCM)instance dht11.DHT11(pin14)try:while True:result instance.read()if result.is_valid():print(ok)print(&quo…
暂无图片
编程学习 ·

ELK简介

ELK简介 ELK是三个开源软件的缩写,Elasticsearch、Logstash、Kibana。它们都是开源软件。不过现在还新增了一个 Beats,它是一个轻量级的日志收集处理工具(Agent),Beats 占用资源少,适合于在各个服务器上搜集日志后传输给 Logstas…
暂无图片
编程学习 ·

Linux 基础

通常大数据框架都部署在 Linux 服务器上,所以需要具备一定的 Linux 知识。Linux 书籍当中比较著名的是 《鸟哥私房菜》系列,这个系列很全面也很经典。但如果你希望能够快速地入门,这里推荐《Linux 就该这么学》,其网站上有免费的电…
暂无图片
编程学习 ·

Windows2022 无线网卡装不上驱动

想来 Windows2022 和 windows10/11 的驱动应该差不多通用的,但是死活装不上呢? 搜一下,有人提到 “默认安装时‘无线LAN服务’是关闭的,如果需要开启,只需要在“添加角色和功能”中,选择开启“无线LAN服务…
暂无图片
编程学习 ·

【嵌入式面试宝典】版本控制工具Git常用命令总结

目录 创建仓库 查看信息 版本回退 版本检出 远程库 Git 创建仓库 git initgit add <file> 可反复多次使用&#xff0c;添加多个文件git commit -m <message> 查看信息 git status 仓库当前的状态git diff 差异对比git log 历史记录&#xff0c;提交日志--pret…
暂无图片
编程学习 ·

用Postman生成测试报告

newman newman是一款基于nodejs开发的可以运行postman脚本的工具&#xff0c;使用Newman&#xff0c;可以直接从命令运行和测试postman集合。 安装nodejs 下载地址&#xff1a;https://nodejs.org/en/download/ 选择自己系统相对应的版本内容进行下载&#xff0c;然后傻瓜式安…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…