aop也是Spring里比较重要的一个点,最近把源码看了下,这里总结一下

使用上主要就下面的点注意下:

  • 相关的Annotaion

    • Around
    • Before
    • After
    • AfterReturning
    • AfterThrowing
    • 执行顺序
  • expression表达式
    • execution
    • args
    • @args()
    • this()
    • target()
    • within()
    • @within()
    • @annotation
  • 处理函数的相关参数
    • ProceedingJoinPoint
    • returning (AfterReturning 可以设置)
    • Exception (AfterThrowing 可以设置)
    • 然后其他的参数,或者target,annotaion之类的,可以通过expression拿到(除了execution)

然后主要针对源码总结一下

1. 注册逻辑

正常通过下面的配置来实现配置

    <aop:aspectj-autoproxy proxy-target-class="true"/>

然后最后会加载AnnotationAwareAspectJAutoProxyCreator

AopNamespaceHandler 会解析aspectj-autoproxy
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); AspectJAutoProxyBeanDefinitionParser 会调用
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 最后会注册一个AnnotationAwareAspectJAutoProxyCreator, 这个就是
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); 注入proxy-target-class (默认false,true的化,直接走cglib动态代理,不走jdk)
注入expose-proxy
解决 自己调用自己不能被spring监控的问题
设为true之后,可以使用 (MyService)(AopContext.currentProxy()).doAnotherFunction()

2. 加强的时机

加强逻辑在AbstractAutoProxyCreator中
proxy逻辑在是在wrapIfNecessary(bean, beanName, cacheKey);
可以看到加强的地方是在

  • SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
  • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

这个调用的地方,和为什么这么使用可以看下 浅述 Spring 代理如何在循环依赖中解决的

3. 具体加强的判断

主要在wrapIfNecessary中

  1. 判断是否需要代理
    过滤Advice等不需要代理的类
  2. 获取所以可以适用于这个类的Advice
  3. 根绝advice生成代理类
// 判断是否这个bean需要被代理
// isInfrastructureClass 如果是基础类,就不需要被代理 Advice, Advisor, AopInfrastructureBean, 或者实现了@Aspect
// shouldSkip 这里处理配置 Advice配置的aspectName
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取所以可以适用于这个类的Advice
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 这里创建代理类
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

3.1 获取所以可以适用于这个类的Advice

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//找到所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到适应于这个bean的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
}
  1. 找到所有的Advisor

    • 找到所有的Advisor类
    • 然后找到@Aspect注解的Class,通过advisorFactory.getAdvisors(factory)获取
      • 得到该class下除了PointCut外所有的函数
      • 按照 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 排序
      • 获取没个函数对应的annotaion 获取该函数的annotaion : Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
      • 对于每个标类注解的InstantiationModelAwarePointcutAdvisorImpl, 这是一个advisor
        • 会针对不同的annotaion返回不通的Advice (atAspectJAdvisorFactory.getAdvice)
        • Before : AspectJMethodBeforeAdvice
        • After : AspectJAfterAdvice
        • Around : AspectJAroundAdvice
        • AfterReturning : AspectJAfterReturningAdvice
        • AfterThrowing : AspectJAfterThrowingAdvice
  2. 找出可以Apply的Advisor
    • 这里就是把Advisor的表达式取出来和bean的class的每个函数match一遍,判断是否符合
  3. 排序Advisor
    • AspectJPrecedenceComparator进行排序

      • 会根绝Aspect类对应的order值来进行排序
      • 同一个类里的会根据Annotaion的类型来排序
        • afterThrow
        • afterReturning
        • after
        • around
        • before
      • 同一个annotaion就是根据名字排序了
        • around, before 是名字在前的在前
        • after系列是 名字在后的在前
          • 这里的目的就是名字在前的先执行

这里画了一个排序的图:
Advice1 的优先级 高于Advice2 

3.2 生成代理

通过cglib或者jdk生产动态代理

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

JdkDynamicAopProxy

实现了InvocationHandler

获取适用的advices
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
然后生成ReflectiveMethodInvocation执行
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

ObjenesisCglibAopProxy

生成对应的callbacks(MethodInterceptor),设置到Enhancer里

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}

浅析 Spring Aop的更多相关文章

  1. 浅析Spring AOP

    在正常的业务流程中,往往存在着一些业务逻辑,例如安全审计.日志管理,它们存在于每一个业务中,然而却和实际的业务逻辑没有太强的关联关系. 图1 这些逻辑我们称为横切逻辑.如果把横切的逻辑代码写在业务代码 ...

  2. 做一个合格的程序员之浅析Spring AOP源代码(十八) Spring AOP开发大作战源代码解析

    事实上上一篇文章价值非常小,也有反复造轮子的嫌疑,网上AOP的实例非常多,不胜枚举,事实上我要说的并非这个,我想要说的就是上一节中spring的配置文件: 我们这边并没实用到我们上几节分析的哪几个AO ...

  3. Spring Boot -- Spring AOP原理及简单实现

    一.AOP基本概念 什么是AOP,AOP英语全名就是Aspect oriented programming,字面意思就是面向切面编程.面向切面的编程是对面向对象编程的补充,面向对象的编程核心模块是类, ...

  4. 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  5. Spring Aop 应用实例与设计浅析

    0.代码概述 代码说明:第一章中的代码为了突出模块化拆分的必要性,所以db采用了真实操作.下面代码中dao层使用了打印日志模拟插入db的方法,方便所有人运行demo. 1.项目代码地址:https:/ ...

  6. 02 浅析Spring的AOP(面向切面编程)

    1.关于AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...

  7. 深入浅析Spring的AOP实现原理

    转载来源:https://www.jb51.net/article/81788.htm AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Or ...

  8. jdk动态代理与cglib代理、spring Aop代理原理-代理使用浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  9. 浅析Spring中AOP的实现原理——动态代理

    一.前言   最近在复习Spring的相关内容,刚刚大致研究了一下Spring中,AOP的实现原理.这篇博客就来简单地聊一聊Spring的AOP是如何实现的,并通过一个简单的测试用例来验证一下.废话不 ...

随机推荐

  1. 0302IT行业虽吃香,能完全享受这块“香"的也很难

    面对现今严峻的就业形势,越来越多的人希望通过职业技能培训或者学历提升来提高自己的综合技能以便能够顺利地应聘到自己理想中的工作. 在2014年十大最热门行业和职业排行榜中IT行业最吃香.在十大行业里,I ...

  2. Objective - C 之延展

    延展:为已有的类新增私有方法,只能在本类中使用 一.创建过程: 二.总结: 1.延展只有.h文件,在其中写新方法的声明,在原本的类(Person)中写方法的实现: 2.上述的方法其实很不安全,因为如果 ...

  3. 找xpath好用的工具(比较少用,针对只能在IE上打开的网站)

    有一些网站只能在IE浏览器里打开,不像firefox那样有好多好用的插件来找元素的xpath,css path等. 当然现在IE也可以,F12出现像firebug那样的窗口,来查看元素. 这里呢在介绍 ...

  4. CentOS7 修改yum源为阿里云

    1,登陆root帐号 2,cd /etc/yum.repo.d 3,mv CentOS-Base.repo CentOS-Base.repo.bak4,wget http://mirrors.aliy ...

  5. RAD Studio 10.3 Rio (BCB & Dephi) 发布啦

    期盼已久的RAD Studio 10.3 Rio  终于发布了: 下载链接:http://altd.embarcadero.com/download/radstudio/10.3/delphicbui ...

  6. 转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)

    PV操作的核心就是 PV操作可以同时起到同步与互斥的作用. 1.同步就是通过P操作获取信号量,V操作释放信号量来进行. 2.互斥其实就是,同时操作P操作,结束后进行V操作即可做到. Java上实现PV ...

  7. 两个list比较相等元素

    1.实现方式 public class list { public static void main(String[] args) { List<String> list1 = new A ...

  8. Jmeter介绍+安装

    JMeter介绍 JMeter 是Apache 基金会Jakarta 上的一个纯Java 开源项目,起初用于基于Web 的压力测试(pressure test),后来其应用范围逐渐扩展到对文件传输FT ...

  9. String Typing CodeForces - 954B

    题意: 给一个字符串,可以复制某一段字符,问最少需要多少步能将其输出,比如abcabcd,先输入abc然后再赋值abc再输入d就只需要5步. 复制的这段字符 必须是从字符串的0位置开始复制的  而且只 ...

  10. [JSOI2007]字符加密 后缀数组

    题面:洛谷 题解: 我们考虑,如果可以将环上每个长度为len的串都提取出来,再做个排序,那这题我们就做出来了! 但是提取$n^2$,怎么办? 考虑破环成链,再扩充为原来的2倍. 然后直接做后缀排序,把 ...