AOP学习笔记
Posted yi-ran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP学习笔记相关的知识,希望对你有一定的参考价值。
概念
什么是AOP
(1) 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2) 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
(3) 使用登录例子说明AOP
登录例子
术语
连接点(join point):类里面那些可以被增强的方法叫连接点。
切入点(point cut):实际被真正增强的方法叫切入点。
通知(advice):
- 实际增强的逻辑部分称为通知(增强)
- 通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知 finally
切面(aspect):是动作,把通知应用到切入点的过程叫切面。
图示:
AOP与OOP的关系
OOP-面向对象程序设计的特点:
- 封装性:将数据与对数据的操作封装到一个实体(类)中,实现高内聚、低耦合。
- 继承性:两个或两个以上类之间的关系,一个类可以从其父类中继承一些特性,比如成员属性和方法。可以简化重复代码,方便管理相似特性
- 多态性:从一个类创建的一组对象中,调用同名函数,不同的对象中做的事情不同。
AOP-面向切面编程的特点:
- 通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
- AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容。
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而降低业务逻辑各部分之间的耦合度,提高程序的可重用性,提高开发效率。
- 将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
这两种设计思想在目标上有着本质的差异,OOD/OOP面向名词领域,AOP面向动词领域。
我的理解:
我们系统中一定包含业务逻辑和与业务关系不大的日志、事务、性能等部分。
对于OOP,类中需要把业务逻辑和非业务的其他逻辑都囊括进去,它解决的是类内部结构和类与类之间的关系。
而AOP,将类中业务的和非业务的逻辑分割开来,非业务的部分给AOP去管理,暴露出业务的实现切面(入口),只需要专注做好业务的部分即可。
AOP底层原理
AOP底层使用动态代理,有两种代理方式
(1)有接口情况,使用JDK动态代理
创建接口实现类代理对象,增强类的方法
(2)没有接口情况,使用CGLIB动态代理
AOP操作(准备)
- Spring框架一般都是基于AspectJ实现AOP操作
(1)什么是AspectJ?
AspectJ不是Spring组成部分,独立于AOP框架。一般把AspectJ和Spring框架一起使用,进行AOP操作
- 基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
- 在项目工程里引入AOP相关的依赖
- 切入点表达式
(1)切入点表达式作用:指定对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符][返回类型][完全限定符][方法名称][参数列表])
举例:
execution(* com.chen.UserDAO.add(..)) // 对add方法增强
execution(* com.chen.UserDAO.*(..)) // 对UserDAO文件中所有方法增强
execution(* com.chen.*.*(..)) // 对com.chen下所有包的所有方法增强
AOP操作—注解方式
- 创建被增强类User
- 创建增强代理类UserProxy
- 进行通知配置
- 创建Spring配置文件,在其中开启注解扫描
- 使用注解创建User和UserProxy对象:在类上加 @Component
- 在增强类UserProxy上添加@Aspect注解
- 在Spring配置文件中开启生成代理对象:增加aspectj-autoproxy节点
<!-- 配置扫描包路径 --> <context:ComponentScan basePackage="com.chen"></context> <!-- 配置aspectj自动代理 --> <aop:aspectj-autoproxy></aop>
- 配置不同类型的通知 @Before,@After
注解类
@Component public class User public void add() System.out.println("add..........");
@Component @Aspect public class UserProxy // 前置通知 @Before(value="execution(* com.chen.User.add(..))") public void addBefore() System.out.println("before.........."); // 最终通知 @After(value="execution(* com.chen.User.add(..))") public void after() System.out.println("After.........."); // 异常通知 @AfterThrowing(value="execution(* com.chen.User.add(..))") public void afterThrowing() System.out.println("AfterThrowing.........."); // 后置通知 @AfterReturning(value="execution(* com.chen.User.add(..))") public void afterReturning() System.out.println("AfterReturning.........."); // 环绕通知 @Around(value="execution(* com.chen.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) System.out.println("Around before.........."); // 被增强方法 proceedingJoinPoint.proceed(); System.out.println("Around After..........");
- 抽取公共的切入点
@Component @Aspect public class UserProxy @Pointcut("execution(* com.chen.User.add(..))") public void pointDemo() // 前置通知 @Before(value="pointDemo()") public void before() System.out.println("before..........");
- 多个增强类对同一个方法增强,在增强类上设置优先级
在增强类上加一个注解:@Order(数字类型的值) 数字越小,优先级越高
@Component @Aspect @Order(1) public class UserProxy1 @Before(value="execution(* com.chen.User.add(..))") public void before() System.out.println("before1.........."); @Component @Aspect @Order(2) public class UserProxy2 @Before(value="execution(* com.chen.User.add(..))") public void before() System.out.println("before2..........");
AOP操作—XML配置方式
- 创建两个类,增强类和被增强类,创建方法
- 在Spring配置文件中创建两个类对象
- 在Spring配置文件中配置切入点
<!-- 创建对象 --> <bean id="user" class="com.chen.User"></bean> <bean id="userProxy" class="com.chen.UserProxy"></bean> <!-- 配置aop增强 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut id="point" expression="execution(* com.chen.User.add(..))"> <!-- 配置切面(把增强类的增强方法应用到切入点上) --> <aop:aspect ref="UserProxy"> <!-- 增强方法是addBefore,应用到的切入点id为point --> <aop:before method="addBefore" pointcut-ref="point"> </aop:aspect> </aop:config>
AOP操作—完全注解方式
增强类和被增强类跟注解方式一致。
增加一个配置类
@Configuration @ComponentScan(basePackages="com.chen") @EnableAspectJAutoProxy(proxyTargetClass=true) public class config
声明:本文参考b 站 尚硅谷React视频。
Spring-AOP学习笔记-01 初识AOP
Spring AOP学习笔记
1 AOP概念和相关术语
Aspect Oriented Programming(AOP):面向切面编程,是面向对象编程(OOP)的一种补充,典型的就是Spring的事务管理。将比如,日志的记录,权限的校验,异常的处理这样非核心功能单独抽离出来,和核心功能解耦,横切在业务代码之上。
相关术语
-
Aspect
切面,在spring的aop里面,切面通常是一个类,对横切关注点的抽象
-
Join point
连接点,就是被拦截的点,简单来说,就是声明在什么时候,因为spring只支持方法的拦截,所以在spring中连接点可以理解为被拦截的方法
-
Pointcut
切入点,也可以叫切点,一般配合切点表达式定位到哪些方法,哪些类,什么地方,是对连接点拦截的定义,可以拦截一个连接点,也可以拦截多个连接点
-
Advice
通知,就是和Join point一起要做的事情,简单来说就是做什么事,就是拦截到连接点后,需要在这个连接点做什么事情
-
Weaving
织入,就是将切面中的通知应用到目标对象(Target Object)上,生成代理对象(AOP Proxy)的过程
2 基于XML配置
使用XML配置文件使用aop,需要加入一下xml约束
<beans xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
注意:需要和之前的spring配置文件合在一起,需要bean的约束文件。
配置好以上的文件后,就可以在spring配置文件中使用aop了,所有的aop配置,都是在aop:config
标签下,首先需要把代理目标类和增强类在ioc中注册,然后在aop中配置bean。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--需要被代理的类-->
<bean id="coreService" class="com.moon.point.CoreService"/>
<!--切面类-->
<bean id="aspect" class="com.moon.aspect.MyAspect"/>
<!--配置aop-->
<aop:config>
<!--配置aop切点-->
<aop:pointcut id="point" expression="execution(public * com.moon..*.*(..))"/>
<!--配置切面切入-->
<aop:aspect ref="aspect">
<!--配置通知方法-->
<aop:before pointcut-ref="point" method="logExecuteTime"/>
</aop:aspect>
</aop:config>
</beans>
3 切点表达式
切点表达式,就是去匹配需要代理的类的方法,可以匹配多个或者单个方法,切点表达式书写在aop切点配置中
<!--配置aop切点 id:切点id expression为切点表达式:表达式在execution()里书写-->
<aop:pointcut id="point" expression="execution(public * com.moon..*.*(..))"/>
正常方法签名对应的切点表达式
方法签名 | public void e() |
---|---|
切点表达式 | public void com.moon.point.CoreService.e(…) |
涉及到的通配符
*
:代表所有..
:代表类,参数
常用的表达式:
/* expression="execution(public * com.moon.point.CoreService.*(..))
该切点表示切如的方法为
修饰符 返回值 方法名()
public void com.moon.point.CoreService.e(..)
public * com.moon.point.CoreService.*(..)
* com.moon.*.*.*(..)
*/
//所有类型 所有返回值 com包下moon包下point包下CoreService的全部方法,方法的参数为任意
public * com.moon.point.CoreService.*(..)
//所有类型,所有返回值 com包下moon包下全部的包和类的全部方法,方法的参数为任意
* com.moon..*.*(..)
//所有类型,所有返回值 com包下moon包下全部的包和类的e方法,方法的参数为任意
* com.moon..*.e(..)
以上是关于AOP学习笔记的主要内容,如果未能解决你的问题,请参考以下文章