AOP扫盲(一)

目录:
一 AOP的定义
二 AOP/OOP区分
三AOP的两种继承体系
四 AOP切面构成要素
五 AOP的两种代理和三种时期
六 AOP 的两种实现方式
一.AOP的定义
AOP(面向切面编程),是Spring框架中一个非常重要的内容,它是通过预编译方式和运行期间动态代理实现程序的维护程序功能统一的技术。
Aop的作用:提高业务的可扩展性,降低业务逻辑各部分之间的耦合度(扩业务,松耦合
主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
二AOP/OOP
OOP(面向对象编程)(核心单元是类)针对业务处理过程中的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
AOP(核心是切面)是处理业务当中的某个步骤,以获得逻辑过程中各部分之间降低耦合性的隔离效果。
三 Aop 的两种继承体系
1.纵向继承体系:例如:if…else…纵向抽取代码之间的关联关系非常密切。
在这里插入图片描述
2.横向抽取
横向抽取也是代码提取的一种方式,不过这种方式不会修改主要业务逻辑代码,只是在此基础上添加一些与主要的业务逻辑无关的功能,AOP 采取横向抽取机制,补充了传统纵向继承体系(OOP)无法解决的重复性 代码优化(性能监视、事务管理、安全检查、缓存),将业务逻辑和系统处理的代码(关闭连接、事务管理、操作日志记录)解耦。
在这里插入图片描述
AOP切面构成要素
切面=切入点+通知
1.切入点(aop的核心)表达式:(4种,2种常用)
a.Bean 按照某个bean(类)拦截 粗粒度
b within(包名.类名) 按照类拦截 粗粒度
c. executation(返回值类型 包名。类名。方法名(参数列表))细粒度
d: @annotation(包名.注解名) 细粒度
2.Spring Aop 中的通知分类:
1.前置通知(Before Advice): 在目标方法被调用前调用通知功能; 相关的类org.springframework.aop.MethodBeforeAdvice
2.后置通知(After Advice): 在目标方法被调用之后调用通知功能;相关的类org.springframework.aop.AfterReturningAdvice
3.返回通知(After-returning): 在目标方法成功执行之后调用通知功能;
4.异常通知(After-throwing): 在目标方法抛出异常之后调用通知功能;相关的类org.springframework.aop.ThrowsAdvice
5.环绕通知(Around): 把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能相关的类org.aopalliance.intercept.MethodInterceptor
附代码:
public void saveUser(User user){
userMapper.insert(user);
}
public void updateUser(User user){
userMapper.update(user);
}
@component
@Aspect
public class TxAspect{
@ PointCut(“execution(com.cy.service….*(…”)
public Object around**(ProceedingJoinPoint jp)**{//目标对象
try{
TX.begin();
jp.proceed();//让目标方法执行
TX.commit();
}catch(){
TX.rollback();
}

}

五 AOP的两种代理和三种时期
JDK和CGLIB代理(详见设计模式)
编译期: 切面在目标类编译时被织入,这种方式需要特殊的编译器。AspectJ 的织入编译器就是以这种方式织入切面的。
类加载期: 切面在目标类加载到 JVM 时被织入,这种方式需要特殊的类加载器( ClassLoader ),它可以在目标类引入应用之前增强目标类的字节码。
运行期: 切面在应用运行的某个时期被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象,Spring AOP 采用的就是这种织入方式。
六 AOP 的两种实现方式
AOP 采用了两种实现方式:静态织入(AspectJ 实现)和动态代理(Spring AOP实现)

AspectJ

AspectJ 是一个采用Java 实现的AOP框架,它能够对代码进行编译(一般在编译期进行),让代码具有AspectJ 的 AOP 功能,AspectJ 是目前实现 AOP 框架中最成熟,功能最丰富的语言。ApectJ 主要采用的是编译期静态织入的方式。在这个期间使用 AspectJ 的 acj 编译器(类似 javac)把 aspect 类编译成 class 字节码后,在 java 目标类编译时织入,即先编译 aspect 类再编译目标类。

Spring AOP 实现

Spring AOP 是通过动态代理技术实现的,而动态代理是基于反射设计的。Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理,分别来理解一下

JDK动态代理:Spring AOP的首选方法。每当目标对象实现一个接口时,就会使用JDK动态代理。目标对象必须实现接口
CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理。
Spring 对 AOP的支持

Spring 提供了两种AOP 的实现:基于注解式配置和基于XML配置

@AspectJ 支持

为了在Spring 配置中使用@AspectJ ,你需要启用Spring支持,以根据@AspectJ切面配置Spring AOP,并配置自动代理。自动代理意味着,Spring 会根据自动代理为 Bean 生成代理来拦截方法的调用,并确保根据需要执行拦截。

可以使用XML或Java样式配置启用@AspectJ支持。在任何一种情况下,都还需要确保AspectJ的aspectjweaver.jar 第三方库位于应用程序的类路径中(版本1.8或更高版本)。

开启@AspectJ 支持

使用@Configuration 支持@AspectJ 的时候,需要添加 @EnableAspectJAutoProxy 注解,就像下面例子展示的这样来开启 AOP代理

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}
也可以使用XML配置来开启@AspectJ 支持

aop:aspectj-autoproxy/
默认你已经添加了 aop 的schema 空间,如果没有的话,你需要手动添加

<?xml version="1.0" encoding="UTF-8"?>

<!-- bean definitions here -->
声明一个切面

在启用了@AspectJ支持的情况下,在应用程序上下文中定义的任何bean都具有@AspectJ方面的类(具有@Aspect注释),Spring会自动检测并用于配置Spring AOP。

使用XML 配置的方式定义一个切面

<aop:aspect />
使用注解的方式定义一个切面

@Aspect
public class MyAspect {}
切面(也就是用@Aspect注解的类)就像其他类一样有属性和方法。它们能够包含切入点,通知和介绍声明。

通过自动扫描检测切面
你可以在Spring XML 配置中将切面类注册为常规的bean,或者通过类路径扫描自动检测它们 - 与任何其他Spring管理的bean相同。然而,只是注解了@Aspect 的类不会被当作bean 进行管理,你还需要在类上面添加 @Component 注解,把它当作一个组件交给 Spring 管理。
定义一个切点

一个切点由两部分组成:包含名称和任何参数以及切入点表达式的签名,该表达式能够确定我们想要执行的方法。在@AspectJ注释风格的AOP中,切入点表达式需要用@Pointcut注解标注(这个表达式作为方法的签名,它的返回值必须是 void)。

@Pointcut(“execution(* transfer(…))”) // 切入点表达式
private void definePointcut() {}// 方法签名
切入点表达式的编写规则如下:

现在假设我们需要配置的切点仅仅匹配指定的包,就可以使用 within() 限定符来表示,如下表达式所述:

请注意我们使用了 && 操作符把 execution() 和 within() 指示器连接在一起,表示的是 和 的关系,类似的,你还可以使用 || 操作来表示 或 的关系, 使用 ! 表示 非 的关系。

除了within() 表示的限定符外,还有其它的限定符,下面是一个限定符表

AspectJ 描述符 描述
arg() 限制连接点匹配参数为指定类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配的AOP代理的bean引用为指定类型的类
target 限制连接点匹配目标对象为指定类型的类
@target() 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型
@annotationn 限定匹配带有指定注解的连接点
使用XML配置来配置切点

aop:config
<aop:aspect ref = “”>
<aop:poincut id = “” expression=“execution(** com.cxuan.aop.definePointcut(…))”/>
</aop:aspect>
</aop:config>
声明一个通知

通知是和切入点表达式相互关联,用于在方法执行之前,之后或者方法前后,方法返回,方法抛出异常时调用通知的方法,切入点表达式可以是对命名切入点的简单引用,也可以是在适当位置声明的切入点表达式。下面以一个例子来演示一下这些通知都是如何定义的:

上面的例子就很清晰了,定义了一个 Audience 切面,并在切面中定义了一个performance() 的切点,下面各自定义了表演之前、表演之后返回、表演失败的时候进行通知,除此之外,你还需要在main 方法中开启 @EnableAspectJAutoProxy 来开启自动代理。

除了使用Java Config 的方式外,你还可以使用基于XML的配置方式

当然,这种切点定义的比较冗余,为了解决这种类似 if…else… 灾难性的业务逻辑,你需要单独定义一个aop:pointcut,然后使用 pointcut-ref 属性指向上面那个标签,就像下面这样

环绕通知

在目标方法执行之前和之后都可以执行额外代码的通知。在环绕通知中必须显式的调用目标方法,目标方法才会执行,这个显式调用时通过ProceedingJoinPoint来实现的,可以在环绕通知中接收一个此类型的形参,spring容器会自动将该对象传入,注意这个参数必须处在环绕通知的第一个形参位置。

环绕通知需要返回返回值,否则真正调用者将拿不到返回值,只能得到一个null。下面是环绕通知的一个示例

<aop:around method=“around” pointcut-ref=“pc1”/>
public Object around(ProceedingJoinPoint jp) throws Throwable{
System.out.println(“1 – around before…”);
Object obj = jp.proceed(); //–显式的调用目标方法
System.out.println(“1 – around after…”);
return obj;
}

发布了11 篇原创文章 · 获赞 3 · 访问量 1329

猜你喜欢

转载自blog.csdn.net/qq_43614498/article/details/104912050