spring之面向切面:AOP(1)

本文涉及的产品
应用实时监控服务-用户体验监控,每月100OCU免费额度
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 【1月更文挑战第15天】一、场景模拟1、声明接口2、创建实现类3、创建带日志功能的实现类4、提出问题二、代理模式1、概念2、静态代理3、动态代理4、测试三、AOP概念及相关术语1、概述2、相关术语①横切关注点②通知(增强)③切面④目标⑤代理⑥连接点⑦切入点3、作用

文章目录

前言

一、场景模拟

1、声明接口

2、创建实现类

3、创建带日志功能的实现类

4、提出问题

二、代理模式

1、概念

2、静态代理

3、动态代理

4、测试

三、AOP概念及相关术语

1、概述

2、相关术语

①横切关注点

②通知(增强)

③切面

④目标

⑤代理

⑥连接点

⑦切入点

3、作用

总结


前言

一、场景模拟

1、声明接口

2、创建实现类

3、创建带日志功能的实现类

4、提出问题

二、代理模式

1、概念

2、静态代理

3、动态代理

4、测试

三、AOP概念及相关术语

1、概述

2、相关术语

①横切关注点

②通知(增强)

③切面

④目标

⑤代理

⑥连接点

⑦切入点

3、作用


一、场景模拟

搭建子模块:spring6-aop

1、声明接口

声明计算器接口Calculator,包含加减乘除的抽象方法

publicinterfaceCalculator {
intadd(inti, intj);
intsub(inti, intj);
intmul(inti, intj);
intdiv(inti, intj);
}

2、创建实现类

publicclassCalculatorImplimplementsCalculator {
@Overridepublicintadd(inti, intj) {
intresult=i+j;
System.out.println("方法内部 result = "+result);
returnresult;
    }
@Overridepublicintsub(inti, intj) {
intresult=i-j;
System.out.println("方法内部 result = "+result);
returnresult;
    }
@Overridepublicintmul(inti, intj) {
intresult=i*j;
System.out.println("方法内部 result = "+result);
returnresult;
    }
@Overridepublicintdiv(inti, intj) {
intresult=i/j;
System.out.println("方法内部 result = "+result);
returnresult;
    }
}

3、创建带日志功能的实现类

publicclassCalculatorLogImplimplementsCalculator {
@Overridepublicintadd(inti, intj) {
System.out.println("[日志] add 方法开始了,参数是:"+i+","+j);
intresult=i+j;
System.out.println("方法内部 result = "+result);
System.out.println("[日志] add 方法结束了,结果是:"+result);
returnresult;
    }
@Overridepublicintsub(inti, intj) {
System.out.println("[日志] sub 方法开始了,参数是:"+i+","+j);
intresult=i-j;
System.out.println("方法内部 result = "+result);
System.out.println("[日志] sub 方法结束了,结果是:"+result);
returnresult;
    }
@Overridepublicintmul(inti, intj) {
System.out.println("[日志] mul 方法开始了,参数是:"+i+","+j);
intresult=i*j;
System.out.println("方法内部 result = "+result);
System.out.println("[日志] mul 方法结束了,结果是:"+result);
returnresult;
    }
@Overridepublicintdiv(inti, intj) {
System.out.println("[日志] div 方法开始了,参数是:"+i+","+j);
intresult=i/j;
System.out.println("方法内部 result = "+result);
System.out.println("[日志] div 方法结束了,结果是:"+result);
returnresult;
    }
}

4、提出问题

①现有代码缺陷

针对带日志功能的实现类,我们发现有如下缺陷:

  • 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
  • 附加功能分散在各个业务功能方法中,不利于统一维护

②解决思路

解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。

③困难

解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。

二、代理模式

1、概念

①介绍

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

使用代理后:

②生活中的代理

  • 广告商找大明星拍广告需要经过经纪人
  • 合作伙伴找大老板谈合作要约见面时间需要经过秘书
  • 房产中介是买卖双方的代理

③相关术语

  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。

2、静态代理

创建静态代理类:

publicclassCalculatorStaticProxyimplementsCalculator {
// 将被代理的目标对象声明为成员变量privateCalculatortarget;
publicCalculatorStaticProxy(Calculatortarget) {
this.target=target;
    }
@Overridepublicintadd(inti, intj) {
// 附加功能由代理类中的代理方法来实现System.out.println("[日志] add 方法开始了,参数是:"+i+","+j);
// 通过目标对象来实现核心业务逻辑intaddResult=target.add(i, j);
System.out.println("[日志] add 方法结束了,结果是:"+addResult);
returnaddResult;
    }
}

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

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

3、动态代理

生产代理对象的工厂类:

publicclassProxyFactory {
privateObjecttarget;
publicProxyFactory(Objecttarget) {
this.target=target;
    }
publicObjectgetProxy(){
/*** newProxyInstance():创建一个代理实例* 其中有三个参数:* 1、classLoader:加载动态生成的代理类的类加载器* 2、interfaces:目标对象实现的所有接口的class对象所组成的数组* 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法*/ClassLoaderclassLoader=target.getClass().getClassLoader();
Class<?>[] interfaces=target.getClass().getInterfaces();
InvocationHandlerinvocationHandler=newInvocationHandler() {
@OverridepublicObjectinvoke(Objectproxy, Methodmethod, Object[] args) throwsThrowable {
/*** proxy:代理对象* method:代理对象需要实现的方法,即其中需要重写的方法* args:method所对应方法的参数*/Objectresult=null;
try {
System.out.println("[动态代理][日志] "+method.getName()+",参数:"+Arrays.toString(args));
result=method.invoke(target, args);
System.out.println("[动态代理][日志] "+method.getName()+",结果:"+result);
                } catch (Exceptione) {
e.printStackTrace();
System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                } finally {
System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                }
returnresult;
            }
        };
returnProxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

4、测试

@TestpublicvoidtestDynamicProxy(){
ProxyFactoryfactory=newProxyFactory(newCalculatorLogImpl());
Calculatorproxy= (Calculator) factory.getProxy();
proxy.div(1,0);
//proxy.div(1,1);}

三、AOP概念及相关术语

1、概述

AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2、相关术语

①横切关注点

分散在每个各个模块中解决同一样的问题,如用户验证、日志管理、事务处理、数据缓存都属于横切关注点。

从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。

这个概念不是语法层面的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。

②通知(增强)

增强,通俗说,就是你想要增强的功能,比如 安全,事务,日志等。

每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。

  • 前置通知:在被代理的目标方法执行
  • 返回通知:在被代理的目标方法成功结束后执行(寿终正寝
  • 异常通知:在被代理的目标方法异常结束后执行(死于非命
  • 后置通知:在被代理的目标方法最终结束后执行(盖棺定论
  • 环绕通知:使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置

③切面

封装通知方法的类。

④目标

被代理的目标对象。

⑤代理

向目标对象应用通知之后创建的代理对象。

⑥连接点

这也是一个纯逻辑概念,不是语法定义的。

把方法排成一排,每一个横切位置看成x轴方向,把方法从上到下执行的顺序看成y轴,x轴和y轴的交叉点就是连接点。通俗说,就是spring允许你使用通知的地方

⑦切入点

定位连接点的方式。

每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物(从逻辑上来说)。

如果把连接点看作数据库中的记录,那么切入点就是查询记录的 SQL 语句。

Spring 的 AOP 技术可以通过切入点定位到特定的连接点。通俗说,要实际去增强的方法

切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

3、作用

  • 简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。
  • 代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了。

总结

以上就是spring之面向切面:AOP(1)的相关知识点,希望对你有所帮助。

积跬步以至千里,积怠惰以至深渊。时代在这跟着你一起努力哦!

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
20天前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
45 5
|
24天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
52 8
|
24天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
24天前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
36 5
|
24天前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
35 4
|
1月前
|
安全 Java 编译器
什么是AOP面向切面编程?怎么简单理解?
本文介绍了面向切面编程(AOP)的基本概念和原理,解释了如何通过分离横切关注点(如日志、事务管理等)来增强代码的模块化和可维护性。AOP的核心概念包括切面、连接点、切入点、通知和织入。文章还提供了一个使用Spring AOP的简单示例,展示了如何定义和应用切面。
123 1
什么是AOP面向切面编程?怎么简单理解?
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
48 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
1月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
37 1
|
3月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP