spring源码系列8:AOP源码解析之代理的创建(上)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: spring源码系列8:AOP源码解析之代理的创建(上)

回顾


首先回顾:

JDK动态代理与CGLIB动态代理

Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别

我们得知 JDK动态代理两要素:Proxy+InvocationHandler CGLB动态代理两要素:Enhancer + MethodInterceptor(Callback)

springAOP底层是通过动态代理和CGLB代理实现的。也就是spring最终的落脚点还应该是在Proxy+InvocationHandler 或者Enhancer + MethodInterceptor上。

带着这个期待我们看看spring是如何组织AOP的,并在动态代理之上建立一个AOP体系的。


概念的理解:


  • 通知:  通知可以理解增强器, 就是做的额外工作.
  • 连接点: 可以允许切面插入的点, 这个点可以是方法调用时, 抛出异常时等.
  • 切点: 并不是所有的连接点都需要被切面插入, 切点就是定义哪些连接点可以插入切面.

总结为:从所有连接点中选出部分连接点,  进行拦截,执行额外操作。


组件的理解:


AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范.

注意:各种组件非常之多. 我只把自认为涉及到主线理解的组件列出


AOP联盟规范定义组件

通知(增强器):   不要纠结于太多. 就统一理解为拦截器或者增强器。

image.png

spring定义组件

1.Pointcut定义哪些连接点可以插入切面。提供ClassFilter 与MethodMatcher两种匹配器,匹配连接点。

2.Advisor :  包装Advice和Pointcut .语义:  在哪里拦截, 插入什么样的增强器(在哪里做什么)Advisor=Advice+Pointcut分为

  • IntroductionAdvisor: 引介增强,在不修改某个类的情况下, 让其具备某接口的功能。
  • PointcutAdvisor: 与切点有关的Advisor

3.TargetSource: 对目标对象的封装。

4.Advised接口 : 包装 Advisor  与 TargetSource。 实现类AdvisedSupport:从其两个属性上,真切看出其封装了  Advisor  与 TargetSource

  • TargetSource targetSource = EMPTY_TARGET_SOURCE; 表示目标对象
  • private List advisors = new ArrayList(); 存储Advisor

5.AopProxyAOP代理对象

  • 分JDK代理(JdkDynamicAopProxy)
  • Cglib代理(CglibAopProxy)


image.png

JdkDynamicAopProxy与CglibAopProxy都实现了AopProxy的getProxy()方法,用于返回真正的代理对象。

6.AopProxyFactoryAOP代理策略工厂类。根据条件选择使用JDK还是Cglib的方式来创建代理对象


image.png

7.ProxyCreatorSupport:  从其语义上理解,对创建代理对象的支持。我们从其继承关系上看看他是如何提供支持的。

  • ProxyConfig:  提供aop配置属性。
  • AdvisedSupport:继承ProxyConfig,实现了Advised接口。封装通知(Advise)和TargetSource,并提供对他们的操作
  • ProxyCreatorSupport: 包含AopProxyFactory,AopProxyFactory策略工厂提供对JdkDynamicAopProxy与CglibAopProxy的创建


image.png


8.AbstractAutoProxyCreator: 从其继承关系。我们分析下这个组件。

  • 首先他是一个(BeanPostProcessor)InstantiationAwareBeanPostProcessor 所以他会在spring的Bean生产线createBean()过程中被执行。在BeanDefinition创建Bean的过程中进行拦截,根据要求创建出代理对象。
  • Aware:  可以获取到BeanFactory仓库, 与BeanClassLoader加载器。
  • ProxyCreatorSupport,继承了创建代理的功能。

关于BeanPostProcessor与InstantiationAwareBeanPostProcessor的理解,还是深刻理解Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别


image.png

小结

如果总结下组件之间的关系:

开发人员定义切面信息--》spring解析出Advice,切点等配置信息--》AopProxyFactory根据配置创建代理对象--》代理方法执行。

这也是springAOP大部分工作内容。

笼统来看:

  • 《1》定义的解析:
  • 《2》代理的创建:
  • 《3》代理的执行:

下面我们重点看看定义的解析与代理的创建。


代理的生成过程:


代理的执行过程: 我们还是以springboot环境下的AOP实现来讲讲AOP的过程.

1.配置AOP的扩展器,拦截BeanDefiniiton创建Bean的过程:AnnotationAwareAspectJAutoProxyCreator:

首先配置AOP环境

@EnableAspectJAutoProxy注解上的@Import(AspectJAutoProxyRegistrar.class)引入AspectJAutoProxyRegistrar类.AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口. 所以其registerBeanDefinitions()会有一些注入BeanDefiniiton的操作 . registerBeanDefinitions()方法会向仓库中注入一个AnnotationAwareAspectJAutoProxyCreator.

@Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//注入AnnotationAwareAspectJAutoProxyCreator扩展器
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    AnnotationAttributes enableAspectJAutoProxy =
        AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
      AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    }
    if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
      AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    }
  }

AnnotationAwareAspectJAutoProxyCreator 间接继承了AOP扩展工具AbstractAutoProxyCreator, 是一个BeanPostProcessor。

AbstractAutoProxyCreator:

  • 是一个BeanPostProcessor,可以拦截Bean创建过程
  • 继承了ProxyCreatorSupport具有代理类的创建能力。

这样:AOP环境有了。


2.拦截生产过程,创建AOP对象:

createBean()生产线在创建Bean的过程中. 会执行所有的BeanPostProcessor. AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator)作为一个BeanPostProcessor也在此时执行.

Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别讲过. 实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor的会有5个方法伴随Bean创建过程且执行顺序。postProcessBeforeInstantiation() -->postProcessAfterInstantiation-->postProcessPropertyValues-->postProcessBeforeInitialization()-->postProcessAfterInitialization()

过程:

(2.1)首先执行的是postProcessBeforeInstantiation 实例化前置处理方法

@Override
  public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);
    if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
      if (this.advisedBeans.containsKey(cacheKey)) {
        return null;
      }
      if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return null;
      }
    }
    if (beanName != null) {
      TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
      if (targetSource != null) {
        this.targetSourcedBeans.add(beanName);
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
      }
    }
    return null;
  }

主要分为两部分: (2.1.1)先判断是否应该代理

  • isInfrastructureClass(beanClass)如果是AOP基础设施类, 不代理。指的是Advice、Pointcut、Advisor等AOP相关定义类不应该创建代理
  • shouldSkip()应该跳过的类,不代理。判断的依据:默认是都不跳过的. 子类可能重写其判断依据.AnnotationAwareAspectJAutoProxyCreator的父类AnnotationAwareAspectJAutoProxyCreator重写了shouldSkip方法(《1》并伴随切面定义的解析)。

重点看看shouldSkip()

/*
1.首先查找适于当前Bean的Advisor .通findCandidateAdvisors()去查找
    findCandidateAdvisors()会经过两个渠道获取Advisors.
      > BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans():是从仓库中找实现了Advisor类的Advisor
      > BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()会从仓库中取出@Aspect注解的切面类,解析出Advisor
   重点说一下其中buildAspectJAdvisors
        >遍历BeanFactory仓库中的BeanDefinition,根据其类型判断其是否是isAspect(): 判断条件是类是否被@Aspect注释,并且没有被aspectj编译过
        >如果是, 根据当前BeanDefinition创建一个(AspectJAdvisorFactory)BeanFactoryAspectInstanceFactory工厂对象.
        >使用AspectJAdvisorFactory 工厂创建List<Advisor>
        >上文已经说过Advisor=Advice+Pointcut, Advice 就是对通知的封装(@Before...), Pointcut 是对切点的封装.
  小结:这次知道我们定义一个切面类, 被解析什么样子了吧
2.判断找到的CandidateAdvisors中有没有当前BeanDefinition,有的话就跳过。
*/
@Override
  protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
      if (advisor instanceof AspectJPointcutAdvisor) {
        if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
          return true;
        }
      }
    }
    return super.shouldSkip(beanClass, beanName);
  }

(2.1.2) 判断是否有自定义的 TargetSource。 如果有自定义TargetSource ,将当前beanName放入targetSourcedBeans缓存中,直接走创建代理的分支,不会走createBean去创建Bean,这里就是给一个机会。 关于自定义TargetSource这个分支暂时不讲。

if (beanName != null) {
      TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
      if (targetSource != null) {
        this.targetSourcedBeans.add(beanName);
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
      }
    }

总结postProcessBeforeInstantiation工作内容:

  • 解析切面定义
  • 提供一个机会直接返回代理对象,不走createBean()流水线。自定义TargetSource

(2.2)postProcessAfterInstantiation

  • return true ;

(2.3)postProcessBeforeInitialization

  • 返回Bean没有做处理

(2.4)postProcessAfterInitialization() (敲黑板,重点


相关文章
|
27天前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
53 5
|
1月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
1月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
44 5
|
1月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
45 4
|
3月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
245 2
|
3天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
10天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
55 14
|
1月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
50 1
SpringBoot入门(7)- 配置热部署devtools工具
|
1月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
48 2
 SpringBoot入门(7)- 配置热部署devtools工具