2w字长文给你讲透了配置类为什么要添加 @Configuration注解,是时候应该安排一下了!

Spring 用的爽不爽?在你爽的同时,你也知道为什么这么爽,在 Spring 中,@Configuration 是一个重重重要的注解,那么配置类为什么要添加 @Configuration 注解呢?本篇文章就带你 get 这个点。

不加 @Configuration 导致的问题

我们先来看看如果不在配置类上添加 @Configuration 注解会有什么问题,代码示例如下:

不添加 @Configuration 注解运行结果:

create dmzService
create A by dmzService
create dmzService

添加 @Configuration 注解运行结果:

create dmzService
create A by dmzService

在上面的例子中,我们会发现没有添加 @Configuraion注解时dmzService被创建了两次。

这是因为第一次创建是被 Spring 容器所创建的,Spring 调用这个 dmzService() 创建了一个 Bean 被放入了单例池中(没有添加其它配置默认是单例的)。
第二次创建是 Spring 容器在创建 a 时调用了a(),而 a() 又调用了 dmzService() 方法。
这样的话,就出现问题了。

第一,对于 dmzService 而言,它被创建了两次,打破了单例的条件。

第二,对于 a 而言,它所依赖的 dmzService 不是 Spring 所管理的,而是直接调用的一个普通的 java 方法创建的普通对象。这个对象没有被 Spring 对象管理,首先它的域(Scope)定义失效了,其次它没有经过一个完整的生命周期,那么我们所定义所有的 Bean 的后置处理器都没有作用到它身上,其中就包括了完成 AOP 的后置处理器,所以 AOP 也失效了。

上面的分析不能说服你的话,我们可以看看官方在 @Bean 上给出的这一段注释

首先,Spring 就在注释中指出了,通常来说,BeanMethod 一般都声明在一个由 @Configuration 注解标注的类中,在这种情况下,BeanMethod 可能直接引用了在同一个类中申明的 beanMethod , 就像本文给出的例子那样,a() 直接引用了 dmzService(),我们重点再看看划红线的部分,通过调用另外一个 beanMethod 进入的 Bean的引用会被保证是遵从域定义以及 AOP 语义的,就像 getBean 所做的那样。这是怎么实现的呢?在最后被红线标注的地方也有说明,是通过在运行时期为没有被 @Configuration 注解标注的配置类生成一个 CGLIB 的子类。

源码分析
那么,Spring 是在什么时候创建的代理呢?到目前为止我们应该没有进入 Spring 启动流程的任何关键代码,那么我们不妨带着这个问题继续往下看。目前来说我们已经阅读到了Spring执行流程图中的3-5步,也就是org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors方法。其执行逻辑如下:

在之前的分析中我们已经知道了,这个方法的主要作用就是执行 BeanFactoryPostProcessor 中的方法,首先执行的是 BeanDefinitionRegistryPostProcessor(继承了BeanFactoryPostProcessor)的postProcessBeanDefinitionRegistry方法,然后执行postProcessBeanFactory方法。

那么目前为止容器中有哪些 BeanFactoryPostProcessor 呢?

Spring 内置的 BeanFactoryPostProcessor 在当前这个时机就已经被注册到容器中的只有一个,就是 ConfigurationClassPostProcessor,在之前的文章中我们已经分析过了它的postProcessBeanDefinitionRegistry方法,这个方法主要是为了完成配置类的解析以及对组件的扫描。

紧接着我们就来看看它的postProcessBeanFactory方法做了什么。其源码如下:

enhanceConfigurationClasses

接下来我们来分析一下 enhanceConfigurationClasses 方法

这段代码非常简单,其目的就是生成一个 enhancedClass(经过了 cglib 增强的 class),然后用其替换目标配置类对应的 BeanDefinition 中的 beanClass 属性。

那么我们接下来需要分析的就是 enhancedClass 是如何生成的。它的核心代码在ConfigurationClassEnhancer中,所以我们要分析下ConfigurationClassEnhancer的源码,在分析它的源码前,我们需要对 cglib 有一定的了解。

1、cglib原理分析
在分析 cglib 前,我们先通过一个例子来认识一下什么是 cglib。

1.1、使用示例

运行结果为:

可以看到,通过上面这种方式,我们已经对 Target 中的方法完成了增

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值