Spring 6.0源码解析之@Configuration

首先写一个启动代码:

public class ConfigurationAnnotationTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationAnnotationTest.class);

    public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigurationAnnotationConfig.class);
ConfigurationAnnotationConfig config = context.getBean(ConfigurationAnnotationConfig.class);
Person person1 = config.person();
Person person2 = config.person();
LOGGER.info("person1 是否等于 person2 ===>> {}", (person1 == person2));
}
}

用 @Configuration 注解的配置类如下:

@Configuration
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}

从上述代码中可以看到,我们通过AnnotationConfigApplicationContext类来为配置类加载Spring应用上下文,创建IOC容器。

所以就从AnnotationConfigApplicationContext类从手,来分析 @Configuration 注解加载的有关源码。

为了方便分析,先放一张 AnnotationConfigApplicationContext 类的 UML 图在这里。

一、注册 ConfigurationClassPostProcessor 源码分析

ConfigurationClassPostProcessorSpring中最重要的后置处理器。@Configuration注解解析涉及到了 ConfigurationClassPostProcessor 类的注册流程。

从启动代码中可以看到,使用了 AnnotationConfigApplicationContext 类的构造方法传入了配置类 ConfigurationAnnotationConfig,来创建了 IOC 容器,那么我们就以此为入口进行分析。

使用的 AnnotationConfigApplicationContext 类构造方法如下:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigurationAnnotationConfig.class);
  1. 进入该构造方法:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}

可以看到,在上述构造方法中,先调用了 AnnotationConfigApplicationContext 类的无参构造方法 this()

  1. 分析这个 this(),源码如下:
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotationConfigApplicationContext 的无参构造函数中,主要做了这些事情:

  • 实例化 AnnotatedBeanDefinitionReader 类的成员变量 readerreader主要是为了解析带有注解的 Bean 的 BeanDefinition,并将其注册到 Bean 工厂中。
  • 实例化 ClassPathBeanDefinitionScanner 类的成员变量 scannerscanner会扫描指定包下的类,并将符合过滤条件的类注册到IOC容器内。

注:StartupStep 接口主要作用是为了跟踪应用程序的启动顺序。

分析实例化 reader 这个成员变量的代码,也就是如下代码片段:

this.reader = new AnnotatedBeanDefinitionReader(this);

  1. 调用了 AnnotatedBeanDefinitionReader 的构造方法:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
  1. 其中又调用了 AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) 构造方法,源码如下:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

在该构造方法中,最重要的就是最后一句代码 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);,将 BeanDefinitionRegistry 类型的registry传入使用。通过前面的代码跟踪可知,this.registry对象的本质是 AnnotationConfigApplicationContext 类对象的实例。

注:根据上文 AnnotationConfigApplicationContext 类的 UML 图可得知,AnnotationConfigApplicationContext 类继承了 GenericApplicationContextGenericApplicationContext 类 又实现了BeanDefinitionRegistry 接口。

  1. 分析 AnnotationConfigUtils 调用的 registerAnnotationConfigProcessors(BeanDefinitionRegistry registry)方法,源码如下:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
  1. 继续分析调用的 registerAnnotationConfigProcessors 方法,这个方法的源码很长,省略部分源码,如下:
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor"; public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) { // ....省略其他代码.... Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
} // ....省略其他代码.... return beanDefs;
}

这里只展示了这个方法中涉及到的 ConfigurationClassPostProcessor 类注册到IOC的相关代码。

可以看到,调用了 registerPostProcessor 方法,从方法名就可以看出,注册后置处理器。进入这个方法。

  1. registerPostProcessor方法的源码如下:
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}

可以看到,调用了 registry 参数的 registerBeanDefinition 方法来注册了 ConfigurationClassPostProcessor

代码跟踪到这里,先来整理一下思路。从上面的整条链路上来看,registry 参数实际上就是 AnnotationConfigApplicationContext 类的实例,definition 参数实际上是带着 ConfigurationClassPostProcessor类的 RootBeanDefinition 实例。

  1. 进入注册方法 registerBeanDefinition,源码如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// .....
}

是调用了BeanDefinitionRegistry接口的registerBeanDefinition方法。

在之前的 UML 图中可以知道,AnnotationConfigApplicationContext 类继承了 GenericApplicationContextGenericApplicationContext 类 又实现了BeanDefinitionRegistry 接口,所以跳转到GenericApplicationContext类的实现。

  1. 源码如下:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

可以看到,实际上是调用了 DefaultListableBeanFactory 类的 registerBeanDefinition 方法。this.beanFactoryDefaultListableBeanFactory 类的实例。

  1. 分析 DefaultListableBeanFactory 类的 registerBeanDefinition 方法,主要源码如下:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
// ... 省略其他代码 ... BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// ... 省略其他代码 ... this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// ... 省略其他代码 ...
this.beanDefinitionMap.put(beanName, beanDefinition);
// ... 省略其他代码 ...
} // ... 省略其他代码 ... }

通过这段代码可以看到,其实向 SpringIOC容器中注册Bean,就是向beanDefinitionMap对象中增加元素。beanDefinitionMap对象的本质是一个 ConcurrentHashMap 对象:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);

key是beanName的名字,value就是定义的Bean。在这里注册的就是 ConfigurationClassPostProcessor 类。

通过代码跟踪,我们可以知道在 AnnotationConfigApplicationContext 类的无参构造函数中,完成了 ConfigurationClassPostProcessor 类的注册。

那么到这里,涉及到的 ConfigurationClassPostProcessor 后置处理器的注册过程源码分析结束。

二、注册 @Configuration 配置类源码分析

从启动代码中可以看到,使用了 AnnotationConfigApplicationContext 类的构造方法传入了配置类 ConfigurationAnnotationConfig,来创建了 IOC 容器。

调用的构造方法如下:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}

在之前已经分析过了 this() 构造函数方法,主要是完成了 后置处理器 ConfigurationClassPostProcessor 的注册,接下来分析 register 对配置类 ConfigurationAnnotationConfig 的注册。

  1. 进入 register(componentClasses) 方法:
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register").tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}

主要代码是调动了 this.reader.register(componentClasses) 方法,传入了 componentClasses 进行注册。

  1. 分析 reader 对象的 register 方法。

注:reader 对象在这里就是 AnnotatedBeanDefinitionReader 的实例化对象

public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}

register 方法中循环遍历传入的可变参数,每次循环都会调用 registerBean 方法。

  1. 分析 registerBean 方法
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}

registerBean 中又调用了 doRegisterBean 方法。

  1. 分析 doRegisterBean 方法
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// ... 省略其他代码 ...
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // ... 省略其他代码 ... BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

可以看到,主要是调用了 AnnotationConfigUtils.applyScopedProxyMode() 方法和 BeanDefinitionReaderUtils.registerBeanDefinition() 方法。

AnnotationConfigUtilsapplyScopedProxyMode方法主要是为了解析 Bean 中的@Scope注解,应用 @Scope注解中的 ProxyMode属性。这里不做重点讲解。

  1. 主要解析 BeanDefinitionReaderUtils.registerBeanDefinition() 方法:
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
} }

可以看到,这边也使用了 registryregisterBeanDefinition 方法向 IOC 容器中注册了 Bean。从上面的跟踪代码可知,调用 registry.registerBeanDefinition() 方法注册的 Bean 其实就是ConfigurationAnnotationConfig配置类。

而这部分的注册源码逻辑与之前注册 ConfigurationClassPostProcessor 类的代码相同,同样是调用了 DefaultListableBeanFactory 类的 registerBeanDefinition 方法,不再重复分析。

至此我们可以看到,这部分就是对 ConfigurationAnnotationConfig 配置类的 Bean 进行了注册。

三、实例化流程源码分析

上面分析了注册 ConfigurationClassPostProcessor 后置处理器的源码与注册 ConfigurationAnnotationConfig 配置类的源码,接下来继续分析,Spring IOC 容器在刷星时,会实例化 @Configuration 注解标注的类。

  1. 继续从这个构造函数开始:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}

可以看到,是调用了 refresh() 这个方法来刷新 Spring IOC 容器。

  1. 进入 refresh() 方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 预处理操作,包括初始化环境变量、处理系统属性、设置属性访问器等等
prepareRefresh();
// 调用 obtainFreshBeanFactory 方法获取一个新的 BeanFactory 对象,该对象用于保存所有 Bean 的定义信息和实例化对象。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory的准备工作
prepareBeanFactory(beanFactory); try {
// 是在对 bean 工厂进行准备以及初始化之后的一个补充处理,用于允许子类对 bean 工厂做一些自定义的处理,以满足特定的应用场景
// 当我们集成 AbstractApplicationContext 类时,可以通过重写 postProcessBeanFactory() 方法来进行自定义处理。
// 如果在这个方法中将某个 bean 的属性值修改了,那么在后面读取该 bean 的属性值时,就会读到被修改过的属性值。
// 总的来说, postProcessBeanFactory() 方法是一个非常灵活的扩展点,允许我们通过自定义的方式对 bean 工厂进行处理,从而实现一些特定的应用场景。
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 用于调用所有实现了 BeanFactoryPostProcessor 接口的类的 postProcessBeanFactory 方法
// 是执行处理 BeanFactoryPostProcessor 的核心方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor(Bean的后置处理器),用于拦截bean创建过程
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
initMessageSource();
// 初始化事件派发器
initApplicationEventMulticaster();
// 空方法,可以用于子类实现在容器刷新时自定义逻辑
onRefresh();
// 注册时间监听器,将所有项目里面的ApplicationListener注册到容器中来
registerListeners();
// 初始化所有剩下的单实例bean,单例bean在初始化容器时创建,原型bean在获取时(getbean)时创建
finishBeanFactoryInitialization(beanFactory);
// 完成BeanFactory的初始化创建工作,IOC容器就创建完成
finishRefresh();
}
// ... 省略部分代码 ...
}
}

refresh() 方法是在 AbstractApplicationContext 容器中实现的,里面做了很多的事情。

由上面的代码解析可以看出,在 refresh 方法中,invokeBeanFactoryPostProcessors 方法是执行处理 BeanFactoryPostProcessor 后置处理器的核心方法,在前面的解析中可知注册了 ConfigurationClassPostProcessor 后置处理器,所以这里重点关注 invokeBeanFactoryPostProcessors 的执行过程。

  1. 进入 invokeBeanFactoryPostProcessors 方法。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

其中又调用了 PostProcessorRegistrationDelegate 类的 invokeBeanFactoryPostProcessors 静态方法。

  1. 进入 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 定义一个记录已经调用过的 BeanFactoryPostProcessor 的 Set,用于防止重复调用。
Set<String> processedBeans = new HashSet<>(); // ... 省略部分代码 ...
// 调用普通的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); // ... 省略部分代码 ...
}

invokeBeanFactoryPostProcessors 方法主要用于调用 BeanFactoryPostProcessor 接口实现类的 postProcessBeanFactory 方法,处理 BeanFactory

如上代码可知,在该方法中又调用了 PostProcessorRegistrationDelegate 类的另一个 invokeBeanFactoryPostProcessors 方法。

  1. 进入 invokeBeanFactoryPostProcessors 方法:
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanFactory(beanFactory);
postProcessBeanFactory.end();
}
}

可以看到,在该方法中会去遍历所有的 BeanFactoryPostProcessor 集合,并调用元素的 postProcessBeanFactory 方法,出传入 beanFactory 来实例化对象。

从上面的代码解析来看,这边调用的 BeanFactoryPostProcessor 接口实现类为 ConfigurationClassPostProcessor 类,所以调用实现的是 ConfigurationClassPostProcessor 类的 postProcessBeanFactory 方法。

  1. 解析 ConfigurationClassPostProcessor 类的 postProcessBeanFactory 方法。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
} enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

postProcessBeanFactory 方法中又调用了 enhanceConfigurationClasses 方法。

  1. 解析 enhanceConfigurationClasses 方法。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// ... 省略部分代码 ...
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}

可以看出这段代码中,主要是用 ConfigurationClassEnhancer 对象调用 enhance 方法来生成代理类,也就是使用 CGLib 生成代理类。

  1. 解析 enhance 方法。
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}

可以看到调用了 createClass 方法,该方法用于创建代理类。在调用这个方法之前先调用了 newEnhancer 方法来实例化一个 Enhancer 对象。

  1. 先看 newEnhancer 方法。
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(configSuperClass);
// 设置接口
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}

newEnhancer 方法主要是用于生成 CGLib 动态代理 Enhancer 对象,后续会使用 Enhancer 对象生成代理类。

从源码中可以看出,newEnhancer 方法为要生成的代理类设置了父类和接口。

设置的接口是 EnhancedConfiguration 类,EnhancedConfiguration 类又继承了 BeanFactoryAware 接口,所以在之后,生成的代理类中可以调用 BeanFactoryAware 接口的 setBeanFactory 方法来获取到 beanFactory 对象。

  1. 接着来看 createClass 方法。
private Class<?> createClass(Enhancer enhancer) {
// 创建代理类
Class<?> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}

createClass 方法中,调用了 enhancer.createClass 方法创建了代理类。

enhancer.createClass 方法是CGLib的方法,创建的代理类目标类的子类,所以这里创建出来的代理类是目标类的子类。

  1. 关注下 CALLBACKS 这个参数。
static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};

可以看到 CALLBACKS 这个参数其实是个 Callback 类型的数组,数组中的每个元素都是 Callback 类型。同时 BeanMethodInterceptorBeanFactoryAwareMethodInterceptor 类也是拦截器类型。

BeanMethodInterceptor 类实现了 MethodInterceptor 接口和 ConditionalCallback 接口,主要作用是对标注了 @Bean 的注解方法进行拦截,执行 intercept 方法来生成 Bean 的实例对象。

  1. 浅看一下 BeanMethodInterceptor 类的源码
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable { // ... 省略部分代码 ...
// 如果已经创建了 Bean 的代理实例对象,则调用父类的方法
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// ... 省略部分代码 ...
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
} return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
// ... 省略部分代码 ...
}

上述代码可以保证在类上添加 @Configuration 注解后,只会为一个类生成一个代理对象,也就是能保证标注了 @Configuration 注解的类生成的代理类是单例模式的。

因为使用 CGLib 类创建出来的代理类是目标类的子类,所以第一次执行上述代码片段时,会调用 cglibMethodProxy.invokeSuper 方法执行父类,也就是执行目标类的方法。

第二次调用上述代码片段时,会调用 resolveBeanReference 方法。

13.最后再简单看下 resolveBeanReference 方法。只挑了重点需要看的地方。

private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) { boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
// ... 省略部分代码 ...
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
// ... 省略部分代码 ...
return beanInstance;
}
// ... 省略部分代码 ...
}

可以看到,在 resolveBeanReference 方法中,会通过 beanFactory 获取已经初始化好的 bean 对象,并将这个已经初始化好的 bean 对象返回,并不会再进行第二次初始化的操作。

四、总结

做一个简单的思维导图。

参考连接:【冰河的星球】https://articles.zsxq.com/id_88k0ww2tsr6n.html

[Spring 6.0源码解析] @Configuration注解源码解析的更多相关文章

  1. Spring源码之@Configuration注解解析

    1.前言 ​ Spring注解开发中,我们只需求要类上加上@Configuration注解,然后在类中的方法上面加上@Bean注解即可完成Spring Bean组件的注册.相较于之前的xml配置文件定 ...

  2. Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析

    一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...

  3. Configuration注解类 Bean解析顺序

    @PropertySource 加载properties @ComponentScan 扫描包 @Import 依赖的class @ImportResource 依赖的xml @Bean 创建bean ...

  4. Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器

    承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...

  5. Spring 源码(7)Spring的注解是如何解析的?

    上一篇 https://www.cnblogs.com/redwinter/p/16196359.html 介绍了BeanFactoryPostProcessor的执行过程,这篇文章介绍Spring中 ...

  6. 【译】Spring 4 基于TaskScheduler实现定时任务(注解)

    前言 译文链接:http://websystique.com/spring/spring-job-scheduling-with-scheduled-enablescheduling-annotati ...

  7. 8 -- 深入使用Spring -- 2...6 Spring 4.0 增强的自动装配和精确装配

    8.2.6 Spring 4.0 增强的自动装配和精确装配 Spring提供了@Autowired 注解来指定自动装配,@Autowired可以修饰setter方法.普通方法.实例变量和构造器等.当使 ...

  8. 7 -- Spring的基本用法 -- 12... Spring 3.0 提供的表达式语言(SpEL)

    7.12 Spring 3.0 提供的表达式语言(SpEL) Spring表达式语言(简称SpEL)是一种与JSP 2 的EL功能类似的表达式语言,它可以在运行时查询和操作对象图.支持方法调用和基本字 ...

  9. Spring源码解析 – @Configuration配置类及注解Bean的解析

    在分析Spring 容器创建过程时,我们知道容器默认会加载一些后置处理器PostPRocessor,以AnnotationConfigApplicationContext为例,在构造函数中初始化rea ...

  10. 异步任务spring @Async注解源码解析

    1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...

随机推荐

  1. 如何通过canvas实现电子签名

    想要实现一个电子签名,可以支持鼠标签名,还能类似书法效果线条有粗有细,同时可以导出成图片. 一.实现连贯的划线 1)首先需要注册鼠标下压.鼠标放开.鼠标移出和鼠标移动事件,通过鼠标下压赋值downFl ...

  2. zzuli 1907: 小火山的宝藏收益

    ***题意:中文的 做法:邻接表+DFS,就相当于搜一棵树,比较一下当前结点得到的宝藏多还是子树下面得到的宝藏多,仔细想想就是水题*** #include<iostream> #inclu ...

  3. java进阶(9)--数组

    一.基本概念: 1.数字为引用数据类型 2.数组实际上是一个容器,可以同时容纳多个元素 3.数组可存储基本数据类型,也可以存储引用数据类型的数据 4.数组一旦创建.长度不可变.且数组中元素类型必须统一 ...

  4. ElasticSearch 映射类型及数据类型区分

    本文为博主原创,未经允许不得转载: 1.ES 中的映射可以分为动态映射和静态映射 动态映射:在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段.类型.长度.主键等,最后才能基 ...

  5. nginx 工作原理及特点

    本文为博主原创,未经允许不得转载: nginx 简介:是一个高性能 HTTP 和 反向代理 服务器. Nginx 特点是占有内存少,并发能力强,事实上 Nginx 的并发能力确实在同类型的网页服务器中 ...

  6. 浏览器兼容 : IE 5 到 IE 9

    <!--[if IE]> <link href="ie.css" rel="stylesheet"> <![endif]--> ...

  7. [转帖]各个版本Windows系统中自带的.NET Framework版本

    ① Windows Server : Windows Server版本 自带的.NET Framework 版本 Windows Server 2022 .NET Framework 4.8 Wind ...

  8. [转帖]使用 Dumpling 导出数据

      16 Contributors 使用数据导出工具 Dumpling,你可以把存储在 TiDB 或 MySQL 中的数据导出为 SQL 或 CSV 格式,用于逻辑全量备份.Dumpling 也支持将 ...

  9. [转帖]INSERT IGNORE INTO 与 INSERT INTO

    INSERT IGNORE INTO 会忽略数据库中已经存在 的数据,如果数据库没有数据,就插入新的数据,如果有数据的话就跳过当前插入的这条数据.这样就可以保留数据库中已经存在数据,达到在间隙中插入数 ...

  10. [转帖]Tomcat部署及优化

    目录 一.Tomcat简介 1 Tomcat的三大核心组件 2 Java Servlet 3 JSP全称Java Server Pages 4 Tomcat 功能组件结构 5 Tomcat 请求过程 ...