Spring企业开发核心框架-下

news2024/11/22 9:56:34

五、Spring AOP面向切面编程

1、场景设定和问题复现

①准备AOP项目

项目名:Spring-aop-annotation

②声明接口

/**
 *       + - * / 运算的标准接口!
 */
public interface Calculator {    
    int add(int i, int j);    
    int sub(int i, int j);   
    int mul(int i, int j);    
    int div(int i, int j);
    
}

③实现接口

/**
 * 实现计算接口,单纯添加 + - * / 实现! 掺杂其他功能!
 */
public class CalculatorPureImpl implements Calculator {    
    @Override
    public int add(int i, int j) {    
        int result = i + j;    
        return result;
    }    
    @Override
    public int sub(int i, int j) {    
        int result = i - j;    
        return result;
    }    
    @Override
    public int mul(int i, int j) {    
        int result = i * j;    
        return result;
    }    
    @Override
    public int div(int i, int j) {    
        int result = i / j;    
        return result;
    }
}

④声明带日志接口实现

新需求:需要在每一个方法中,添加控制台输出,输出参数和输出计算后的返回值!

/**
 * 在每个方法中,输出传入的参数和计算后的返回结果!
 */
public class CalculatorLogImpl implements Calculator {    
    @Override
    public int add(int i, int j) {    
        System.out.println("参数是:" + i + "," + j);
        int result = i + j;
        System.out.println("方法内部 result = " + result);      
        return result;
    }    
    @Override
    public int sub(int i, int j) {    
        System.out.println("参数是:" + i + "," + j);    
        int result = i - j;    
        System.out.println("方法内部 result = " + result);
        return result;
    }    
    @Override
    public int mul(int i, int j) {    
        System.out.println("参数是:" + i + "," + j);   
        int result = i * j;    
        System.out.println("方法内部 result = " + result);    
        return result;
    }    
    @Override
    public int div(int i, int j) {    
        System.out.println("参数是:" + i + "," + j);    
        int result = i / j;   
        System.out.println("方法内部 result = " + result);        
        return result;
    }
}

⑤代码问题分析

1)代码缺陷

  • 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
  • 附加功能代码重复,分散在各个业务功能方法中,冗余,且不方便统一维护!

2)解决问题

  • 核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。将重复的代码统一提取,并且【动态插入】到每个业务方法!

3)技术困难

  • 解决问题的困难:提取重复附加功能代码到一个类中,可以实现但是如何将代码插入到各个方法中?我们不会,我们需要引用新技术!!!
2、解决技术代理模式

① 代理模式

23种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直视对目标方法进行调用,而是通过代理类间调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

代理场景:

  •  代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。(中介)
    • 动词:指做代理这个动作,或这项工作
    • 名词:扮演代理这个角色的类、对象、方法
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。代理在开发中实现的方式具体有两种:静态代理,动态代理。

② 静态代理

主动创建代理类:

public class CalculatorStaticProxy implements Calculator {    
    // 将被代理的目标对象声明为成员变量
    private Calculator target;    
    public CalculatorStaticProxy(Calculator target) {
        this.target = target;
    }    
    @Override
    public int add(int i, int j) {    
        // 附加功能由代理类中的代理方法来实现
        System.out.println("参数是:" + i + "," + j);    
        // 通过目标对象来实现核心业务逻辑
        int addResult = target.add(i, j);   
        System.out.println("方法内部 result = " + result);   
        return addResult;
    }
    ……

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将其他地方也需要附加日志,那还得再声明更多个静态代理类,那就生产了大量重复代码,日志功能还是分散的,没有统一管理。

③ 动态代理

  • JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口!它会根据目标类的接口动态生成一个代理对象!代理对象和目标对象有相同的接口!(拜把子)
  • cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口!(认干爹)

代理工程:基于jdk代理技术,生成代理对象

public class ProxyFactory<T> {
    //目标对象。具体什么类型由调用者指定
    private T target;
    public ProxyFactory(T target) {
        this.target = target;
    }
    public T getProxy(){
        //1、获取目标对象的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2、获取目标对象所实现的所有对象
        Class<?>[] interfaces = target.getClass().getInterfaces();
        //1、JDK动态代理方式:
        T o = (T)Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler());
        return o;
    }
    public class MyInvocationHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //反射角度:method是目标方法,args是目标方法执行时所需要的参数。
            System.out.println("日志功能,"+method.getName()+"方法执行了,参数为:"+ Arrays.toString(args));
            //核心:目标方法
            Object result = method.invoke(target, args);
            System.out.println("日志功能,"+method.getName()+"方法执行结束,结果为:"+ result);
            return result;
        }
    }
}

④ 代理总结

代理方式可以解决附加功能代码干扰核心代码和不方便统一维护的问题!

它主要是将附加功能代码提取到代理中执行,不干扰目标核心代码。但是我们也发现,无论使用静态代理和动态代理,程序员的工作都比较繁琐,需要自己编写代理工厂等。但是,提前剧透,我们在实际开发中,不需要编写代理代码,我们可以使用SpringAOP框架,它会简化代理的实现!

3、面向切面编程思维(AOP)

1)面向切面编程思想AOP

AOP:Aspect Oriented Programming 面向切面编程

AOP可以说是OOP的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都如此,这种散布在各处的无关的代码被称为横切,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

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

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

相关文章

使用Python绘制太阳系图

使用Python绘制太阳系图 太阳系图太阳系图的优点使用场景 效果代码 太阳系图 太阳系图&#xff08;Sunburst Chart&#xff09;是一种层次结构图表&#xff0c;用于表示数据的分层结构。它使用同心圆表示各个层级&#xff0c;中心圆代表最高层级&#xff0c;向外的圆环代表逐级…

类型转换与数据绑定【Spring源码学习】

simpleTypeConverter 类型转换 SimpleTypeConverter typeConverter new SimpleTypeConverter(); Integer number typeConverter.convertIfNecessary("13",int.class); System.out.println(number);BeanWrapper 通过反射原理为bean赋值&#xff0c;走的是set方法…

使用pyqt5编写一个七彩时钟

使用pyqt5编写一个七彩时钟 效果代码解析定义 RainbowClockWindow 类初始化用户界面显示时间方法 完整代码 在这篇博客中&#xff0c;我们将使用 PyQt5 创建一个简单的七彩数字时钟。 效果 代码解析 定义 RainbowClockWindow 类 class RainbowClockWindow(QMainWindow):def _…

C++ 数据库MySQL 学习笔记(3) - 数据库操作

C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表&#xff0c;是一种虚拟存在的表。视图就像一个窗口&#xff0c;通过这个窗口可以看到系统专门提供的数据&#xff0c;这样用户可以不看整个数据库表中的数据&#xff0c;而只关心对自己有…

【热部署】✈️Springboot 项目的热部署实现方式

目录 &#x1f378;前言 &#x1f37b;一、热部署和手动重启 &#x1f37a;二、热部署的实现 2.1 手动启动热部署 2.2 自动检测热部署 2.3 关闭热部署 &#x1f49e;️三、章末 &#x1f378;前言 小伙伴们大家好&#xff0c;书接上文&#xff0c;通过Springboot 中的 actu…

【Python】已解决:IndexError: list index out of range

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;IndexError: list index out of range 一、分析问题背景 在Python编程中&#xff0c;IndexError: list index out of range 是一个常见的错误。这个错误通常出现…

【Python从入门到进阶】59、Pandas库中Series对象的操作(二)

接上篇《58、Pandas库中Series对象的操作(一)》 上一篇我们讲解了Pandas库中Series对象的基本概念、对象创建和操作&#xff0c;本篇我们来继续学习Series对象的运算、函数应用、时间序列操作&#xff0c;以及Series的案例实践。 一、Series对象的运算 1. 数值型数据的算术运…

基于JSP的体育竞赛成绩管理系统

开头语&#xff1a;你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果有相关需求&#xff0c;文末可以找到我的联系方式。 开发语言&#xff1a;JSP 数据库&#xff1a;MySQL 技术&#xff1a;JSPJava 工具&#xff1a;MyEclipse, Tomcat, MySQL 系统展示 首页 管理…

Windows Ternimal

Windows Ternimal 安装 Windows 终端概述 | Microsoft Learn wt --help在当前目录打开 lextm/windowsterminal-shell: Install/uninstall scripts for Windows Terminal context menu items 打开指定目录 wt -d %USERPROFILE% ohmyposh 美化 1 安装 2 添加 ohmyposh bin…

数字签名解析

1. 概述 数字签名不是手写签名的数字图像&#xff1b; 数字签名是一种可以提供认证的加密形式&#xff0c;是转向完全无纸环境的一个途径&#xff1b; 数字签名机制用以解决伪造、抵赖、冒充和篡改、完整性保护等安全问题。 2. 公钥密码与数字签名的关系 要实现数字签名&#…

【python爬虫实战】爬取豆瓣top250(网站有反爬虫机制肿么办)

关于请求头headers: 值得注意的是&#xff0c;与上一篇 &#xff1a;​​​​​​【python爬虫实战】爬取书店网站的 书名&价格&#xff08;注释详解&#xff09;-CSDN博客 爬取书名不同&#xff0c;这次爬取豆瓣网站必须使用“请求头headers”&#xff0c;不然将没有输…

SSM学习2:依赖注入、依赖自动装配、集合注入、加载properties文件

依赖注入 依赖注入方式 setter注入——引用类型 setter注入——简单类型 public class BookDaoImpl implements BookDao {public void setDatabaseName(String databaseName) {this.databaseName databaseName;}public void setNum(int num) {this.num num;}private Stri…

【图像超分辨率】一个简单的总结

文章目录 图像超分辨率(Image Super-Resolution, ISR)1 什么是图像超分辨率&#xff1f;2 图像超分辨率通常有哪些方法&#xff1f;&#xff08;1&#xff09;基于插值的方法&#xff08;2&#xff09;基于重建的方法&#xff08;3&#xff09;基于学习的方法&#xff08;LR im…

jenkins 发布服务到linux服务器

1.环境准备 1.1 需要一台已经部署了jenkins的服务器&#xff0c;上面已经集成好了&#xff0c;jdk、maven、nodejs、git等基础的服务。 1.2 需要安装插件 pusblish over ssh 1.3 准备一台额外的linux服务器&#xff0c;安装好jdk 2.流程描述 2.1 配置jenkins&#xff0c;包括p…

统计是一门艺术(参数假设检验)

1.参数假设检验 在总体分布已知的情况下&#xff0c;对分布中未知参数的检验。 &#xff08;1&#xff09;相关基本概念 零假设/原假设与对立假设/备择假设&#xff1a; 任务&#xff1a;根据样本作出是否接受H0 复合假设与简单假设&#xff1a; 否定域/拒绝域与接受域&…

Python:谈谈常规滤波器(带通、低通、高通、带阻)的用法

一、滤波器的作用 滤波器在信号处理中用于移除或减少信号中的噪声&#xff0c;同时保持信号的某些特性。滤波器通常用于音频、视频和图像处理等领域。滤波器根据其 designed for different purposes and can be divided into several types, such as lowpass filters, highpass…

【Unity设计模式】✨使用 MVC 和 MVP 编程模式

前言 最近在学习Unity游戏设计模式&#xff0c;看到两本比较适合入门的书&#xff0c;一本是unity官方的 《Level up your programming with game programming patterns》 ,另一本是 《游戏编程模式》 这两本书介绍了大部分会使用到的设计模式&#xff0c;因此很值得学习 本…

Linux rpm与yum

一、rpm包管理 rpm用于互联网下载包的打包及安装工具&#xff0c;它包含在某些Linux分发版中。它生成具有.RPM扩展名的文件。RPM是RedHat Package Manager (RedHat软件包管理工具&#xff09;的缩写&#xff0c;类似windows的setup.exe&#xff0c;这一文件格式名称虽然打上了R…

Python pip install模块时C++编译环境问题

pip install模块时C编译环境问题 在接触和使用python后&#xff0c;常常会通过pip install命令安装第三方模块&#xff0c;大多数模块可以直接安装&#xff0c;但许多新同学仍会遇见某些模块需要实时编译后才能安装&#xff0c;如报错信息大概是缺乏C编译环境&#xff0c;本文则…

Golang-GMP

GMP调度 golang-GMP语雀笔记整理 GMP调度设计目的&#xff0c;为何设计GMP?GMP的底层实现几个核心数据结构GMP调度流程 设计目的&#xff0c;为何设计GMP? 无论是多进程、多线程目的都是为了并发提高cpu的利用率&#xff0c;但多进程、多线程都存在局限性。比如多进程通过时…