Spring Core-AOP原理与实践

目录

目标

AOP

简介

相关概念

主要类

使用方式

如何确定advice的执行顺序


目标

介绍springcore中的AOP,阐述通过源码了解的原理。

AOP

简介

AOP是对OOP的补充,从切面的角度考虑编程结构。OOP的单元是class,AOP的单元是aspect,aspect切面便于针对关注点进行模块化。
文档链接:https://docs.spring.io/spring/docs/5.0.4.RELEASE/spring-framework-reference/core.html#aop

相关概念

  • join point

程序执行中的一个关注点,如方法的执行或异常的控制。SpringAOP,指的是方法的执行。

  • aspect

对关注点的模块化,模块中包括关注点描述和对应的行为。例如事务管理。

SpringAOP,通过xml配置或@Aspect来实现。

  • advice

在确切的点,由aspect执行的具体行为。advice的类型包括around before after。许多AOP框架,包括SpringAOP,将advice视为interceptor拦截器,并且对join point维持一个拦截器链

  • type
  • before advice
    • 在join point之前执行的advice,无法控制执行流程进入joinpoint
    • @Before("pointcut()")
      public void doBefore(JoinPoint joinPoint) throws Exception {
             // do something
      }

  • after returning advice
    • 在join point正常返回之后执行的advice
    • @AfterReturning(pointcut = "pointcut()")
      public void doAfterReturning(JoinPoint joinPoint) {
             // do something
      }

  • after throwing advice
    • 在join point抛出异常后执行的advice
  • after finally advice
    • 忽略join point的返回方式(不管正常返回还是抛出异常),在join point退出后执行advice
  • around advice
    • 在join point之前和之后都可以执行的advice,威力最大的advice。它负责决定执行流程是否进入join point,是否通过返回自定义数据或抛出自定义异常的方式截断joinpoint的执行
    • @Around("pointcut()")
      public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
          // do something
          // 可以直接返回,中断调用
      
          return joinPoint.proceed();
      }

type选择建议:选择最适合需求的advice,这样让代码简洁,而且避免错误。

  • pointcut

一个描述,用于匹配感兴趣的join point。advice必须与pointcut描述关联,并且在由pointcut匹配到的joinpoint处执行,例如具体名称的方法执行。

  • introduction

允许在类型的代表之上,引入额外的方法或域。SpringAOP允许在advisedobject上引入任何接口。

  • target object

被一个或多个aspect advised的对象。因为SpringAOP使用了运行时代理,所以target指的是被代理的对象。

  • AOP proxy

为了实现aspect的约定,由AOP框架创建的对象。SpringAOP,指的是JDK动态代理或CGLIB代理。

SpringAOP只能将method作为joinpoint;如果需要异常和field作为joinpoint,需要选择AspectJ。

主要类

  • DefaultAopProxyFactory

默认aop代理工厂,创建Cglib代理或jdk动态代理

class DefaultAopProxyFactory implements AopProxyFactory
AopProxy createAopProxy(AdvisedSupport config){}

当AdvisedSupport中optimize=true或proxyTargetClass=true或没有设置proxy interfaces,创建CglibProxy,否则Jdk动态代理

  • CglibAopProxy

  • 生成代理类实例的方法;
  • 定义了一些拦截器类(如动态AOP拦截器)
class CglibAopProxy implements AopProxy

CglibAopProxy.DynamicAdvisedInterceptor 动态AOP拦截器

  • 获取方法级别关注点的所有切面行为
  • 生成CglibMethodInvocation并执行process

CglibAopProxy.CglibMethodInvocation extends ReflectiveMethodInvocation

  • DefaultAdvisorChainFactory

org.springframework.aop.framework.DefaultAdvisorChainFactory

getInterceptorsAndDynamicInterceptionAdvice,获取关注点的所有切面行为

  • ReflectiveMethodInvocation

class ReflectiveMethodInvocation implements ProxyMethodInvocation

Object proceed(),依次执行切面行为,最后执行关注点

  • JoinPoint

org.aspectj.lang.JoinPoint

用于自定义advice方法的参数,代表当前关注点信息

  • ProceedingJoinPoint

org.aspectj.lang.ProceedingJoinPoint

用于自定义around advice方法的参数,代表当前关注点信息

  • MethodInvocationProceedingJoinPoint

spring中joinpoint proceedingJoinPoint的实现类,真实持有当前关注点信息。

使用方式

使用AspectJ

  • 开启Spring支持

需要org.aspectJ的jar

现在已经不使用xml文件了。

spring xml添加
<aop:aspectj-autoproxy/>
可能还需要
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"

  • @aspect声明类作为面

  • @pointcut声明方法为pointcut

3种类型

  1. kind,如execution(规定接口与方法)
@Pointcut("execution(* com.xxxxx.mapper.DealMapper.save*(..)) || execution(* com.xxxx.mapper.DealMapper.update*(..))")
  1. scope,如within(规定包)
  2. context,如this,target(规定proxy traget 参数等类型)

最佳实践

  1. scope+kind
  • 声明方法为advice

    • @Before
    • @AfterReturning
    • @AfterThrowing
    • @After
    • @Around

必须明确pointcut,可进行参数传递

使用autoconfig + StaticMethodMatcherPointcutAdvisor

使用起来也是很简单,一些依赖AOP实现的中间件会使用到该方式。 

public class MyAdvisor extends StaticMethodMatcherPointcutAdvisor {

    public MyAdvisor() {
        // 添加切面行为
        setAdvice(new MethodInterceptor() {

            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("MyAdvisor deal");
                return null;
            }
        });
    }

    /**
     * 匹配类或方法是否满足join point要求
     * @param method
     * @param aClass
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> aClass) {
        boolean match = method.getName().equals("check");
        return match;
    }
}
@Configuration
public class MyAdvisorConfiguration {
    @Bean
    public MyAdvisor myAdvisor(){
        return new MyAdvisor();
    }
}

如何确定advice的执行顺序

依据aspect的order决定,order越大则优先执行
多个aspect时,则按照order决定顺序。一个aspect中的多个advice,无法判断顺序,建议分拆到多个aspect中。

事务

详见后续章节

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值