SpringAOP学习--前言AOP简介

SpringAOP详解+快速入门 本文介绍了 Spring AOP 的实现原理,并通过实例解析详细阐述了其实现过程。在使用 Spring AOP时,我们需要定义切面类,并为需要实现AOP的方法添加注解。 Spring 会自动将切面逻辑插入到这些方法中,从而实现AOP的功能。 阅读详情

AOP简介

AOP是一种思想,一种编程方式。编写一段代码在合适的时机找到切入点然后执行。不直接修改原来的代码,而是在原代码执行的前后执行一段额外的代码。
这么做的好处有:
1.解耦合,系统应求追高内聚低耦合,增强的逻辑独立存在,即插即用,不需要移除掉切点即可,对原有业务无影响(或影响极小)。
2.符合开闭原则,对扩展开放,对修改关闭,不修改原有代码。改代码的代价有些时候比较大。
3.代码复用,可以在不侵入当前代码的情况下复用代码或引入第三方功能从而扩展系统功能

AOP之代理

AOP是通过代理的方式实现的,由代理对象持有原对象,在执行原对象目标方法的前后可以执行额外的增强代码。
代理对象需要是原对象接口的实现或原对象的子类,这样就可以在对象引用处直接替换原对象。
在这里插入图片描述
代理方式分静态代理和动态代理,区别在于代理对象生成方式不同

静态代理:编译期增强,生成可见的代理class,使用代理类替换原有类进行调用。静态代理是手动步枪,打一枪就需要手动换单装填上膛。

动态代理:运行期增强,内存中动态生成代理类,使用反射动态调用原对象方法。动态代理是自动步枪,一次装弹上膛,哒哒哒就完事儿了。

AOP的实现有:AspectJ、JDK动态代理、CGLIB动态代理、JBossAOP、JMangler(后面两种仅限于传说,没接触过)
AspectJ属于静态代理,使用特定编译器在编译期生成代理对象并与源码融在了一起,即修改了class文件。
JDK动态代理必须基于接口,即生成的代理对象是对原对象接口的实现,相当于替换了实现类,面向对象中接口可以替换实现类。
CGLIB动态代理基于继承,即生成的代理对象是原对象的子类,面向对象中子类可以替换父类。

不论是静态代理还是动态代理
AOP均有三个关注点:切面增强内容、何地切入、何时切入
切面增强内容:切面增强逻辑的代码段
何地切入:需要给哪个类哪个方法增强
何时切入:切入发生在何时,方法执行前、执行后、还是执行前后

AOP实现

下面举一个例子,以不使用代理,使用静态代理,使用动态代理看看如何实现

Word类是一个单词本,可以分析出一个字符串包含了单词本中的几个关键词

/**
 * <p>单词本</p>
 *
 * @author nec
 * @date 2021/5/11 10:33
 */
public interface Word {

    /**
     * <p>添加新词</p>
     *
     * @since 2021/5/13 18:11
     * @param word
     * @return
     */
    void addWord(String word);

    /**
     * <p>返回单词本包含的词</p>
     *
     * @since 2021/5/13 18:11
     * @param content
     * @return
     */
    List<String> findKeyWord(String content);
}
public class WordImpl implements Word {
    
    private static List<String> keyWordList = new ArrayList<>();

    @Override
    public void addWord(String word) {
        if (keyWordList.contains(word)) {
            return;
        }

        keyWordList.add(word);
    }

    @Override
    public List<String> findKeyWord(String content) {
        List<String> resultList = new ArrayList<>();
        if (StringUtils.isEmpty(content)) {
            return resultList;
        }

        for (String word : keyWordList) {
            if (content.indexOf(word) > -1) {
                resultList.add(word);
            }
        }

        return resultList;
    }

}

上线一段后,需要对于返回值打印便于我们通过日志排查问题,同时统计热点词汇方便优化需求。

不使用代理处理

最简单的实现为,使用一个日志工具类,代码中调用Word.findKeyWord时,对返回值做处理,或者直接修改findKeyWord方法,return前处理。

对返回值做处理

Word word = createWord();
List<String> keyWordList = word.findKeyWord(content);
MyLogUtil.printResult(content, keyWordList);
MyLogUtil.countResult(content, keyWordList);

直接修改findKeyWord方法,return前处理

@Override
public List<String> findKeyWord(String content) {
    List<String> resultList = new ArrayList<>();
    if (StringUtils.isEmpty(content)) {
        return resultList;
    }

    for (String word : keyWordList) {
        if (content.indexOf(word) > -1) {
            resultList.add(word);
        }
    }

    MyLogUtil.printResult(content, resultList);
    MyLogUtil.countResult(resultList);

    return resultList;
}

上面两种方式其实都不好!打印日志和统计都不是业务逻辑,findKeyWord的核心逻辑没有任何变化,只能算是一种辅助扩展功能,甚至可有可无
如果此类处理大量存在,则会导致:
1.影响代码执行:这种“辅助功能”与业务逻辑执行毫无关系,可一旦发生异常则影响执行结果,还得多做些“保证不产生负面影响”的操作,如捕获异常
2.增加代码复杂度:业务逻辑中侵入了与业务无关的代码,影响阅读,提升业务逻辑复杂度
3.废弃时清理难度大:有天不需要这种“辅助功能”了,还得一一删除排查,确保清理干净,确保没有清理出bug

静态代理方式处理

定义代理类,替换原对象进行调用执行。

public class WordStaticProxy implements Word {

    private Word word;

    public void setWord(Word word) {
        this.word = word;
    }

    @Override
    public void addWord(String word) {
        this.word.addWord(word);
    }

    @Override
    public List<String> findKeyWord(String content) {
        System.out.println("静态代理哦!");
        before();
        List<String> resultList = this.word.findKeyWord(content);
        after(content, resultList);
        return resultList;
    }

    private void before() {
        // TODO
    }

    private void after(String content, List<String> resultList) {
        try {
            MyLogUtil.printResult(content, resultList);
            MyLogUtil.countResult(resultList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

执行静态代理

Word word = createWord();
WordStaticProxy proxy = new WordStaticProxy();
proxy.setWord(word);
List<String> keyWordList = proxy.findKeyWord(content);

动态代理方式处理

定义拦截器并生成代理类,替换原对象进行调用执行,这里使用JDK动态代理。

拦截器

public class WordProxyHandler implements InvocationHandler {

    /**
     * 原对象,被代理对象
     */
    private Object word;

    public WordProxyHandler(Object word) {
        this.word = word;
    }

    /**
     * <p>代理方法</p>
     *
     * @param proxy 生成的代理对象
     * @param method 被代理对象的方法,反射执行invoke需要传入原对象
     * @param args  被代理对象的方法的入参
     * @return
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理哦!");
        before();
        Object result = method.invoke(word, args);
        after(args, result);
        return result;
    }

    private void before() {
        // TODO
    }

    private void after(Object[] args, Object result) {
        try {
            String content = args[0].toString();
            List<String> resultList = (List<String>) result;
            MyLogUtil.printResult(content, resultList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

生成动态代理对象工具类

public class DynamicProxyUtil {

    public static <T> T getProxy(Class<T> clazz, T obj) {
        InvocationHandler wordProxyHandler = new WordProxyHandler(obj);
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, wordProxyHandler);
    }
}

执行动态代理

Word original = createWord();
Word word = DynamicProxyUtil.getProxy(Word.class, original);
List<String> keyWordList = proxy.findKeyWord(content);

测试

public class MainTest {

    private static Word word;

    public static void main(String[] args) {
        String content = "京东的刘强东在肯德基吃啃得起";
        testNormal(content);
        System.out.println("----------------");
        testStaticProxy(content);
        System.out.println("----------------");
        testDynamicProxy(content);
    }

    private static void testNormal(String content) {
        System.out.println("正常执行测试start...");
        init(ProxyType.NORMAL);
        List<String> keyWordList = word.findKeyWord(content);
        try {
            MyLogUtil.printResult(content, keyWordList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("正常执行测试end...");
    }

    private static void testStaticProxy(String content) {
        System.out.println("静态代理执行测试start...");
        init(ProxyType.STATIC_PROXY);
        List<String> keyWordList = word.findKeyWord(content);
        System.out.println("静态代理执行测试end...");
    }

    private static void testDynamicProxy(String content) {
        System.out.println("动态代理执行测试start...");
        init(ProxyType.DYNAMIC_PROXY);
        List<String> keyWordList = word.findKeyWord(content);
        System.out.println("动态代理执行测试end...");
    }

    private static void init(ProxyType proxyType) {
        switch (proxyType) {
            case NORMAL :
                word = createWord();
                break;
            case STATIC_PROXY:
                word = createStaticProxy();
                break;
            case DYNAMIC_PROXY:
                word = createDynamicProxy();
                break;
            default:
                word = createWord();
        }
    }

    private static Word createWord() {
        Word wordTmp = new WordImpl();
        wordTmp.addWord("啃得起");
        wordTmp.addWord("京东");
        wordTmp.addWord("拼多多");
        wordTmp.addWord("马云");
        return wordTmp;
    }

    private static Word createStaticProxy() {
        Word word = createWord();
        WordStaticProxy proxy = new WordStaticProxy();
        proxy.setWord(word);
        return proxy;
    }

    private static Word createDynamicProxy() {
        Word word = createWord();
        return DynamicProxyUtil.getProxy(Word.class, word);
    }

    public enum ProxyType{
        NORMAL,
        STATIC_PROXY,
        DYNAMIC_PROXY
    }
}

测试结果

正常执行测试start…
京东的刘强东在肯德基吃啃得起:出现 2 个关键词
包含的关键词有:啃得起 京东
正常执行测试end…

静态代理执行测试start…
静态代理哦!
京东的刘强东在肯德基吃啃得起:出现 2 个关键词
包含的关键词有:啃得起 京东
静态代理执行测试end…

动态代理执行测试start…
动态代理哦!
京东的刘强东在肯德基吃啃得起:出现 2 个关键词
包含的关键词有:啃得起 京东
动态代理执行测试end…

使用感受

1.aop是一种优秀的编程思想,可以解耦合和提高代码复用作用,编程优雅
2.动态代理使得aop更加简单易用,应用范围广,是目前aop主流用法
3.aop不可滥用,会破坏的程序连贯性。可以用aop默默做一些事,如事务支持、日志打印,如果核心业务逻辑使用aop拆分隔离,则程序不直观不连贯,滥用时维护不见得方便

TLSR8258蓝牙Mesh实战:从SDK下载到自定义通信指令全流程(附避坑指南) 本文详细介绍了TLSR8258蓝牙Mesh开发的完整流程,从SDK下载、环境搭建到自定义通信指令的实现。通过实战案例和避坑指南,帮助开发者快速掌握低功耗蓝牙Mesh网络构建技巧,适用于智能家居、工业监控等物联网场景。 阅读详情

相关推荐

GhidrAssist:AI驱动的逆向工程助手实战指南

逆向工程是分析软件内部工作原理、理解二进制代码逻辑的关键技术,广泛应用于软件安全、恶意代码分析和漏洞挖掘等领域。其核心原理在于通过反编译、控制流与数据流分析等手段,将机器码还原为可理解的高级语言表示。传统逆向分析高度依赖人工经验,面对海量代码时效率低下且易出错。随着大语言模型(LLM)技术的发展,其强大的代码理解与推理能力为自动化逆向分析提供了新的可能。通过将LLM与成熟的逆向工程框架(如Ghidra)相结合,可以构建智能辅助系统,实现代码意图的自动解释、变量/函数的智能重命名以及潜在漏洞模式的辅助识别,从

weixin_42547335的博客 596

Spring-3-AOP和切入点

Spring框架提供的另一个核心功能是支持面向方面的编程(AOP)。AOP通常被称为实施横切关注点的工具。术语横切关注点(crosscutting concerns)是指应用程序中无法从应用程序的其余部分分解并且可能导致代码重复和紧密耦合的逻辑。通过使用AOP模块化各个逻辑部分(称为关注点(concerns)),可以将它们应用于应用程序的多个部分,而无须复制代码或创建硬性依赖关系。

andy的博客 1817

【保姆级教程/代码】使用PRIDE PPP-AR软件解算ZTD、反演GNSS PWV,并评估精度

在本算例中,我下载了BJFS站2024年的IGS ZTD产品,用于评估PRIDE PPP-AR软件解算出ZTD结果的精度。

weixin_43910227的博客 2374

SpringBoot使用AOP控制接口访问次数以及接口幂等性

最近跟朋友聊起接口优化…于是学习总结,记录下来。

weixin_45850829的博客 1373

海康工业相机排雷笔记02-像素格式解析

工业相机使用过程记录 02-像素格式解析 通过将相机输出图像裸数据raw格式直接存图查看 一、黑白/Mono 直接使用相机测试图像存图: 图像中各部分灰度分别为:0、36、73、109、146、182、219、255,以灰度73列为例 (1)Mono 8 该列图像数据为十六进制49,十进制为73,那么Mono 8就是每个像素点占8bit,依次排列。 (2)Mono 10 该列图像数据为十六进制2401,由于相机均为小端数据,实际数据应解析为0124,十进制为292=73*4,那么Mono 10格式为每

yonghuming_66的博客 8360

注册“Oracle Provider for OLE DB”和创建链接服务器

注册“Oracle Provider for OLE DB”和创建链接服务器 在sql server 数据库上创建链接服务器,连接oracle数据库,访问接口需要设置为:“Oracle Provider for OLE DB”。 如果电脑上没有这个驱动,安装一个完整的Oracle11gR2程序是一个有效的方法,但这个64位版本的安装包有2个多G, 相当庞大,如果仅仅...

weixin_30760895的博客 2385

AOP简介

简要的介绍了spring中的AOP,使用案例进行了演示

凉茶铺的博客 2968

squirrel校园二手交易平台

squirrel校园二手交易平台 (适合寻找SSM项目练手的你。) 项目起源:   期末的课程设计,三人一组,我和两个舍友,一时起兴,决定做一个校园二手交易平台,一开始兴致与激情满满,可是后期时间上的冲突,让我们三个人对于这个项目有点累。   这个项目刚定题两天,BezosLee由于通过了360的网上在线笔试,收到了360公司的免费培训邀请,要去北京的360总部进行培训一周,值得庆...

K.SHI的博客 5万+

Spring Aop执行时机及实现方式

实现一 首先我们先写两个切面类:执行时间执行顺序由@Order注解决定,参数越小,顺序越先 @Aspect @Component @Order(0) public class MethodAspect { @Before("execution(public int live.sunhao.calculator.service.CalculatorService.*(..))") publi...

S_Tian的博客 1345

三、STM32F103ZET6最小系统

stm32最小系统除去主控CPU外,需要包含,电源电路,复位电路,BOOT电路,时钟电路(因为stm32有内置时钟,对时钟要求不高的话,可以不要)。NRST引脚其实芯片已经用一个约40K的电阻上拉了,所以理论上来说是不需要再外接上拉电阻的,但我看大家都是有外接上拉的,心里没有底,不管这么多,先预留着。吃过亏,特意查看了芯片手册资料,下图是官方建议的供电方案,图片来自stm32f103zet6数据手册。首先明白目标,单纯的学习软件知识并不是我希望的,我还希望会硬件设计,这样后面才能摆脱开发板。

sevendecsdn的博客 6457

QT实现ftp服务器(附完整源码)

QT实现ftp服务器(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1784

[Spring]Spring AOP学习笔记(2)---5种切入方式、AOP优先级及切面表达式的重用

Spring AOP学习笔记(2)---5种切入方式及AOP优先级 一、5种切入方式 学习了下Spring的AOP的五种切入方式,分别是: (1)Before ---在所拦截方法执行前执行; (2)After ---在所拦截方法执行后执行; (3)AfterRuturning  ---在所拦截方法返回值后,执行; (4)AfterThrowing ---当所拦截方法抛出异常

让勤奋成为习惯 6044

C#串口通信从入门到精通(11)——串口接收的数据存储到本地文件(txt、csv)

本文详细介绍如何将串口通信将数据进行本次存储,主要介绍常用的csv、txt格式文件,由多年实战经验总结,绝对干货!

qq_34059233的博客 7239

SpringAOP学习--SpringAOP简介及原理

前文对AOP做了介绍,实际项目中,一般不会直接上手手动实现aop,而是使用一些高级封装的aop实现,如SpringAOP。 Spring是一个广泛应用的框架,SpringAOP则是Spring提供的一个标准易用的aop框架,依托Spring的IOC容器,提供了极强的AOP扩展增强能力,对项目开发提供了极大地便利。 前文提到AOP的实现有AspectJ、JDK动态代理、CGLIB动态代理,SpringAOP不是一种新的AOP实现,其底层采用的是JDK/CGLIB动态代理。 JDK动态代理回顾 上一篇简单介绍了

u012098021的博客 6万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【Java】SpringAOP —— AOP是什么? 代码实现了SpringAOP

AOP(Aspect Oriented Programming):面向切面编程,它是⼀种思想,它是对某一类事情的集中处理。

The_emperoor_man的博客 1245

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

SpringAOP面向切面编程

介绍面向切面编程的思想(AOP),AOP的组成,SpringAOP的简单演示使用,SpringAOP基于动态代理的实现原理。

trong_ 的烂笔头 2545

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【Spring AOP学习】AOP的组成 && SpringAOP的实现和实现原理

/表示是一个切面:优快云@Component@Slf4j//表示是一个切面:优快云,要结合五大注解使用@Aspect//表示是一个切点:登录功能验证//方法体就是通知小Tips:切点指的是具体要处理的某一类问题:用户登录权限的验证就是一个具体的问题,也就是一个切点。(1)切面上要加@Aspect注解,结合五大注解使用:加@Component;

qq_48479056的博客 556

Java学习:SpringAOP的学习

AOP(Aspcet Oriented Programming):面向切面编程,面向方面编程,其实就是面向特定方法的编程,在不改动源代码的基础上,实现代码的增强,或者是功能的改变。SpringAop是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。动态代理是面向切面编程最主流的实现。

weixin_48800764的博客 1803

Spring AOP(二)AOPAlliance与SpringAOP核心接口介绍

AOP联盟是java对于AOP提供的一系列标准接口,顶层接口有:Advice通知,及其继承接口MethodInterceptor方法拦截器;JointPoint连接点,及其继承接口MethodInvocation。Spring或其他具有AOP概念的框架都会依赖于此,从Spring扩展的接口来看,对于AOP的支持局限于方法的拦截。

sun_tantan的博客 4879

Spring5参考指南:SpringAOP简介

文章目录AOP的概念Spring AOP简介Spring AOP通知类型 写过程序的都知道OOP即面向对象编程。 从最开始的面向过程编程,到后面的面向对象编程,程序的编写方式发生了重大的变化,面向对象编程将业务逻辑封装成一个一个的对象,所有的操作都转换为对对象的操作。 面向对象编程现在使用的非常普遍,一般来说只要是高级语言都支持,但是它也有缺点,比如如果我们想做一些横跨对象的操作(如统计各个对象里...

程序那些事 1万+

Spring AOP

❤️❤️❤️终于到了本专栏最后一个模块——AOP。一、什么是 Spring AOP?在专栏第一篇我们就简单说了Spring框架提供了对AOP的支持,那Spring AOP和AOP有什么不同吗?AOP(Aspect Oriented Programming):面向切面编程,它是⼀种思想,它是对某⼀类事情的集中处理。

冷兮雪的博客 2360

Spring AOP 详解

Spring AOP 详解

yyhgo_的博客 7072

Aop简介 Aop术语 SpringAOP

1.AOP简介 1.AOP (面向切面编程):是一种新的方法论,是对传统OOP(面向对象编程)的补充 2.AOP 的主要编程对象是切面(aspect),而切面模块化横切关注点 3.在应用AOP编程时,任然需要定义公共功能,但可以明确的定义这个功能在哪儿,以什么方式应用,并且不必修改受影响的类,这样以来横切关注点就被模块化到特殊的对象(切面)里。 4.AOP好处: 1.每个事务逻辑位于一个位置,代码不分散,便于维护升级 2.业务模块更简洁,只包含核心业务代码 例如加减乘除的逻辑 1.代理对象:业务逻辑

weixin_46055386的博客 365

SpringAOP超详细教学

SpringAOP 前言 我的这篇AOP博客有大量的图片和例子教会怎么使用AOP 配置那里如果没有学习Maven的话也别急 就是使用maven下载了jar包而已了 你完全可以自己手动导入 如果你有一些代码比如说 事务 或者 日志等操作 需要大量嵌入你的代码前后的话 那么无疑AOP是最好用的 AOP运行流程 : 首先调用前置通知(你可以认为最一开始初始的东西)-&amp;gt;你的逻辑代码(这里先不说环...

TheSevenSky 8514

SpringAOP和AspectJ有什么关系 ?

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉✨特色专栏:🥭本文内容:SpringAOP和AspectJ有什么关系?📚个人知识库:,欢迎大家访问我们知道现在开发都是Spring,讲的最多的也是SpringAOP,在说springAOP前,先了解下AOP是什么?AOP是通过 “预编译方式” 和 “运行期间动态代理” 实现程序功能的统一维护的一种技术。

分享思想,留下痕迹。 1735

SpringAop学习笔记

SpringAop学习笔记,包括代理模式,静态和动态代理,aop的概念详解,执行流程,使用情况,使用方法

2301_77207909的博客 1520
上一篇: Mysql默认事务隔离级别及行锁
下一篇: SpringAOP学习--SpringAOP简介及原理
程序源程序
博客等级 码龄13年 186粉丝 27原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值