术语名词
1-横切关注点
从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。
这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务、异常等。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

2-通知(增强)
每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。
- 前置通知:在被代理的目标方法前执行
- 返回通知:在被代理的目标方法成功结束后执行(**寿终正寝**)
- 异常通知:在被代理的目标方法异常结束后执行(**死于非命**)
- 后置通知:在被代理的目标方法最终结束后执行(**盖棺定论**)
- 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置

3-连接点 joinpoint
这也是一个纯逻辑概念,不是语法定义的。
指那些被拦截到的点。在 Spring 中,可以被动态代理拦截目标类的方法

4-切入点 pointcut
定位连接点的方式,或者可以理解成被选中的连接点!
是一个表达式,比如execution(* com.spring.service.impl.*.*(..))。符合条件的每个方法都是一个具体的连接点。
5-切面 aspect
切入点和通知的结合。是一个类。

6-目标 target
被代理的目标对象。
7-代理 proxy
向目标对象应用通知之后创建的代理对象。
8-织入 weave
指把通知应用到目标上,生成代理对象的过程。可以在编译期织入,也可以在运行期织入,Spring采用后者。
AOP思维,框架,技术相关

Spring-AOP的具体实现
依赖:
<!-- spring-aspects会帮我们传递过来aspectjweaver -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.6</version>
</dependency>
快速实现案例
1,定义增强类
package com.bubu.com.bubu.advice;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/*
* 前置:@Before
* 后置:@AfterReturning
* 异常:@AfterThrowing
* 最后:@After
* 环绕:@Around
* */
@Component
@Aspect //切面注解,不加配置会全部生效
public class LogAdvice {
@Before("execution(* com.bubu.service.Impl.*.*(..))")
public void start(){
System.out.println("方法开始了");
}
@After("execution(* com.bubu.service.Impl.*.*(..))")
public void after(){
System.out.println("方法结束了");
}
@AfterThrowing("execution(* com.bubu.service.Impl.*.*(..))")
public void error(){
System.out.println("方法报错了");
}
}
2,在配置类中进行扫描:
@Configuration
@ComponentScan("com.bubu")
@EnableAspectJAutoProxy //开启aspectj的注解配置
获取切点详细信息
* 前置:@Before * 后置:@AfterReturning * 异常:@AfterThrowing * 最后:@After * 环绕:@Around

package com.bubu.com.bubu.advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAdvice {
@Before("execution(* com..Impl.*.*(..))")
public void before(JoinPoint joinPoint){
//1,获取方法属于类的信息
String simpleName = joinPoint.getTarget().getClass().getSimpleName();
//2,获取方法名称
joinPoint.getSignature().getName();
//3,获取参数列表
Object[] args = joinPoint.getArgs();//获取目标方法参数
System.out.println("Before Advice");
}
@AfterReturning(value = "execution(* com..Impl.*.*(..))",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
System.out.println(result);
System.out.println("After Returning Advice");
}
@After("execution(* com..Impl.*.*(..))")
public void after(JoinPoint joinPoint){
System.out.println("After Advice");
}
@AfterThrowing(value = "execution(* com..Impl.*.*(..))",throwing = "throwable")
public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println(throwable);
System.out.println("After Throwing Advice");
}
}
其中有关切点表达式:

对于切点表达式的提取和复用:

创建储存切点的类:
package com.bubu.pointcut;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyPointCut {
@Pointcut("execution(* com..Impl.*.*(..))")
public void pC1() {}
@Pointcut("execution(* com.bubu.service.Impl.*.*(..))")
public void pC2() {}
}
通过调用切点类的全限定符:
public class LogAdvice {
@Before("com.bubu.pointcut.MyPointCut.pC2()")
public void start(){
System.out.println("方法开始了");
}
@After("com.bubu.pointcut.MyPointCut.pC2()")
public void after(){
System.out.println("方法结束了");
}
@AfterThrowing("com.bubu.pointcut.MyPointCut.pC2()")
public void error(){
System.out.println("方法报错了");
}
}
这样可以实现切点的统一管理
环绕通知
要求有一个返回值
package com.bubu.com.bubu.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TxAroundAdvice {
/*
* 环绕通知,需要在通知中定义目标方法的执行
*
* @param joinPoint 目标方法(获取目标方法信息,多了一个执行方法)
* @return 目标方法的放回值
* */
@Around("com.bubu.pointcut.MyPointCut.pC1()")
public Object around(ProceedingJoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
Object result = null;
try {
//增强代码-》before
System.out.println("开启事务");
result = joinPoint.proceed(args);
System.out.println("结束事务");
}catch(Throwable e){
System.out.println("事务回滚");
throw new RuntimeException(e);
}
return result;
}
}
切面优先级设定
@Order()
里边的数字越小,优先级越高。
使用xml文件的方式实现AOP的功能
<!-- 配置目标类的bean -->
<bean id="calculatorPure" class="com.atguigu.aop.imp.CalculatorPureImpl"/>
<!-- 配置切面类的bean -->
<bean id="logAspect" class="com.atguigu.aop.aspect.LogAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut id="logPointCut" expression="execution(* *..*.*(..))"/>
<!-- aop:aspect标签:配置切面 -->
<!-- ref属性:关联切面类的bean -->
<aop:aspect ref="logAspect">
<!-- aop:before标签:配置前置通知 -->
<!-- method属性:指定前置通知的方法名 -->
<!-- pointcut-ref属性:引用切入点表达式 -->
<aop:before method="printLogBeforeCore" pointcut-ref="logPointCut"/>
<!-- aop:after-returning标签:配置返回通知 -->
<!-- returning属性:指定通知方法中用来接收目标方法返回值的参数名 -->
<aop:after-returning
method="printLogAfterCoreSuccess"
pointcut-ref="logPointCut"
returning="targetMethodReturnValue"/>
<!-- aop:after-throwing标签:配置异常通知 -->
<!-- throwing属性:指定通知方法中用来接收目标方法抛出异常的异常对象的参数名 -->
<aop:after-throwing
method="printLogAfterCoreException"
pointcut-ref="logPointCut"
throwing="targetMethodException"/>
<!-- aop:after标签:配置后置通知 -->
<aop:after method="printLogCoreFinallyEnd" pointcut-ref="logPointCut"/>
<!-- aop:around标签:配置环绕通知 -->
<!--<aop:around method="……" pointcut-ref="logPointCut"/>-->
</aop:aspect>
</aop:config>
3629

被折叠的 条评论
为什么被折叠?



