@Configuration注解
开始之前,先介绍下容器,首先,我们先看一下容器类型
根据打印日志可以看出是AnnotationConfigApplicationContext,进入构造方法
我们看到两个东西:reader、scanner,它们的具体类型如下
。。。。。。
介绍这些,主要是为了引入一个类叫做,ConfigurationClassPostProcessor,这个类实现了BeanFactory PostProcessor,它会在AbstractApplicationContext的refresh()方法(这个方法是IOC容器的启动方法)中执行invokeBeanFactoryPostProcessors(beanFactory) 时被处理,这个类有许多重要的作用,其中一个关键的作用就是扫描类,它会将我们Application类(也就是加了@SpringBootApplication注解的类)以及外来的依赖中的自动配置类加载到容器中,让我deBug看一下。
先准备一下环境,两个配置类,一个在Application类的路径下,另一个为第三方依赖
然后在invokeBeanFactoryPostProcessors(beanFactory)方法打上断点(位于package org.springframework. context.support下的AbstractApplicationContext的refresh()中),观察一下
beanDefinationMaps中的内容
再在ConfigurationClassPostProcessor中的processConfigBeanDefinitions()上打几个断点,
当断点释放到这时,可以看到beanDefinitionNames里多了几个beanDefinition,其中就有我们自己写的类,继续释放断点
释放到这,就可以看到我们第三方依赖的配置类了。
这就结束了吗?当然并没有,接下来,IOC会为@Configuration的类生成代理对象,至于为什么要生成代理对象,相信大家都明白,因为正对于@Bean的方法,若不生成代理对象进行重新,那么每次调用都会是一个新的对象。让我们继续分析。。。
生成代理对象的步骤在enhanceConfigurationClasses方法中,该方法同样ConfigurationClassPostProcessor中。我们只需要关系下面的逻辑
看,这里出现了我们的配置类,继续放行,进入enhance(Cglib)方法
该方法上有一段英文描述,读完以后可以知道,该方法是帮我们生成CGLIB子类的,继续放行,可以看到
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
看看newEnhancer(configClass, classLoader)做了什么,
这个方法就是创建一个生成代理类的对象,设置了父类,设置了接口,至于为啥设置接口,我可以看一下
可以看出这个接口继承了BeanFactoryAware,继承这个接口的作用就是可以让我们的对象可以获得BeanFactory
继续,进入createClass 方法,通过断点可以看出代理对象的类型整数我们的配置类,这里发现一个比较特殊的东西,CALLBACK
看一下BeanMethodInterceptor
进到这里,就差不多了,BeanMethodInterceptor 顾名思义,就是方法拦截器,该拦截器的作用就是去容器里找对应的Bean,然后返回。让我们实验一下,实验代码如下,debug启动,然后Step Into
果然进入到了BeanMethodInterceptor下的intercept方法
最后,介绍一下@Configuration的属性 “proxyBeanMethods”
简答来说,就是当该值为true时,就会生成CGLIB代理对象,对方法进行拦截,每次返回的都是同一个对象,若为false,则不会生成代理对象,原本什么样就是什么样