[Spring 6.0源码解析] @Configuration注解源码解析
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 源码分析
ConfigurationClassPostProcessor
是Spring
中最重要的后置处理器。@Configuration
注解解析涉及到了 ConfigurationClassPostProcessor
类的注册流程。
从启动代码中可以看到,使用了 AnnotationConfigApplicationContext
类的构造方法传入了配置类 ConfigurationAnnotationConfig
,来创建了 IOC
容器,那么我们就以此为入口进行分析。
使用的 AnnotationConfigApplicationContext
类构造方法如下:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigurationAnnotationConfig.class);
- 进入该构造方法:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
可以看到,在上述构造方法中,先调用了 AnnotationConfigApplicationContext
类的无参构造方法 this()
。
- 分析这个 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
类的成员变量reader
。reader
主要是为了解析带有注解的 Bean 的BeanDefinition
,并将其注册到Bean
工厂中。 - 实例化
ClassPathBeanDefinitionScanner
类的成员变量scanner
。scanner
会扫描指定包下的类,并将符合过滤条件的类注册到IOC
容器内。
注:
StartupStep
接口主要作用是为了跟踪应用程序的启动顺序。
分析实例化 reader
这个成员变量的代码,也就是如下代码片段:
this.reader = new AnnotatedBeanDefinitionReader(this);
- 调用了
AnnotatedBeanDefinitionReader
的构造方法:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
- 其中又调用了
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
类继承了GenericApplicationContext
,GenericApplicationContext
类 又实现了BeanDefinitionRegistry
接口。
- 分析
AnnotationConfigUtils
调用的registerAnnotationConfigProcessors(BeanDefinitionRegistry registry)
方法,源码如下:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
- 继续分析调用的
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
方法,从方法名就可以看出,注册后置处理器。进入这个方法。
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
实例。
- 进入注册方法
registerBeanDefinition
,源码如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// .....
}
是调用了BeanDefinitionRegistry
接口的registerBeanDefinition
方法。
在之前的 UML
图中可以知道,AnnotationConfigApplicationContext
类继承了 GenericApplicationContext
,GenericApplicationContext
类 又实现了BeanDefinitionRegistry
接口,所以跳转到GenericApplicationContext
类的实现。
- 源码如下:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
可以看到,实际上是调用了 DefaultListableBeanFactory
类的 registerBeanDefinition
方法。this.beanFactory
是 DefaultListableBeanFactory
类的实例。
- 分析
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);
// ... 省略其他代码 ...
}
// ... 省略其他代码 ...
}
通过这段代码可以看到,其实向 Spring
的 IOC
容器中注册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
的注册。
- 进入
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
进行注册。
- 分析
reader
对象的register
方法。
注:
reader
对象在这里就是AnnotatedBeanDefinitionReader
的实例化对象
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
在 register
方法中循环遍历传入的可变参数,每次循环都会调用 registerBean
方法。
- 分析
registerBean
方法
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
在 registerBean
中又调用了 doRegisterBean
方法。
- 分析
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()
方法。
AnnotationConfigUtils
的applyScopedProxyMode
方法主要是为了解析 Bean 中的@Scope
注解,应用 @Scope注解中的 ProxyMode
属性。这里不做重点讲解。
- 主要解析
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);
}
}
}
可以看到,这边也使用了 registry
的 registerBeanDefinition
方法向 IOC
容器中注册了 Bean
。从上面的跟踪代码可知,调用 registry.registerBeanDefinition()
方法注册的 Bean
其实就是ConfigurationAnnotationConfig
配置类。
而这部分的注册源码逻辑与之前注册 ConfigurationClassPostProcessor
类的代码相同,同样是调用了 DefaultListableBeanFactory
类的 registerBeanDefinition
方法,不再重复分析。
至此我们可以看到,这部分就是对 ConfigurationAnnotationConfig
配置类的 Bean
进行了注册。
三、实例化流程源码分析
上面分析了注册 ConfigurationClassPostProcessor
后置处理器的源码与注册 ConfigurationAnnotationConfig
配置类的源码,接下来继续分析,Spring
IOC
容器在刷星时,会实例化 @Configuration
注解标注的类。
- 继续从这个构造函数开始:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
可以看到,是调用了 refresh()
这个方法来刷新 Spring
IOC
容器。
- 进入
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
的执行过程。
- 进入
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
静态方法。
- 进入
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
方法。
- 进入
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
方法。
- 解析
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
方法。
- 解析
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
生成代理类。
- 解析
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
对象。
- 先看
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
对象。
- 接着来看
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
的方法,创建的代理类目标类的子类,所以这里创建出来的代理类是目标类的子类。
- 关注下
CALLBACKS
这个参数。
static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
可以看到 CALLBACKS
这个参数其实是个 Callback
类型的数组,数组中的每个元素都是 Callback
类型。同时 BeanMethodInterceptor
和 BeanFactoryAwareMethodInterceptor
类也是拦截器类型。
BeanMethodInterceptor
类实现了 MethodInterceptor
接口和 ConditionalCallback
接口,主要作用是对标注了 @Bean
的注解方法进行拦截,执行 intercept
方法来生成 Bean
的实例对象。
- 浅看一下
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注解源码解析的更多相关文章
- Spring源码之@Configuration注解解析
1.前言 Spring注解开发中,我们只需求要类上加上@Configuration注解,然后在类中的方法上面加上@Bean注解即可完成Spring Bean组件的注册.相较于之前的xml配置文件定 ...
- Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析
一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...
- Configuration注解类 Bean解析顺序
@PropertySource 加载properties @ComponentScan 扫描包 @Import 依赖的class @ImportResource 依赖的xml @Bean 创建bean ...
- Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器
承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...
- Spring 源码(7)Spring的注解是如何解析的?
上一篇 https://www.cnblogs.com/redwinter/p/16196359.html 介绍了BeanFactoryPostProcessor的执行过程,这篇文章介绍Spring中 ...
- 【译】Spring 4 基于TaskScheduler实现定时任务(注解)
前言 译文链接:http://websystique.com/spring/spring-job-scheduling-with-scheduled-enablescheduling-annotati ...
- 8 -- 深入使用Spring -- 2...6 Spring 4.0 增强的自动装配和精确装配
8.2.6 Spring 4.0 增强的自动装配和精确装配 Spring提供了@Autowired 注解来指定自动装配,@Autowired可以修饰setter方法.普通方法.实例变量和构造器等.当使 ...
- 7 -- Spring的基本用法 -- 12... Spring 3.0 提供的表达式语言(SpEL)
7.12 Spring 3.0 提供的表达式语言(SpEL) Spring表达式语言(简称SpEL)是一种与JSP 2 的EL功能类似的表达式语言,它可以在运行时查询和操作对象图.支持方法调用和基本字 ...
- Spring源码解析 – @Configuration配置类及注解Bean的解析
在分析Spring 容器创建过程时,我们知道容器默认会加载一些后置处理器PostPRocessor,以AnnotationConfigApplicationContext为例,在构造函数中初始化rea ...
- 异步任务spring @Async注解源码解析
1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...
随机推荐
- 如何通过canvas实现电子签名
想要实现一个电子签名,可以支持鼠标签名,还能类似书法效果线条有粗有细,同时可以导出成图片. 一.实现连贯的划线 1)首先需要注册鼠标下压.鼠标放开.鼠标移出和鼠标移动事件,通过鼠标下压赋值downFl ...
- zzuli 1907: 小火山的宝藏收益
***题意:中文的 做法:邻接表+DFS,就相当于搜一棵树,比较一下当前结点得到的宝藏多还是子树下面得到的宝藏多,仔细想想就是水题*** #include<iostream> #inclu ...
- java进阶(9)--数组
一.基本概念: 1.数字为引用数据类型 2.数组实际上是一个容器,可以同时容纳多个元素 3.数组可存储基本数据类型,也可以存储引用数据类型的数据 4.数组一旦创建.长度不可变.且数组中元素类型必须统一 ...
- ElasticSearch 映射类型及数据类型区分
本文为博主原创,未经允许不得转载: 1.ES 中的映射可以分为动态映射和静态映射 动态映射:在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段.类型.长度.主键等,最后才能基 ...
- nginx 工作原理及特点
本文为博主原创,未经允许不得转载: nginx 简介:是一个高性能 HTTP 和 反向代理 服务器. Nginx 特点是占有内存少,并发能力强,事实上 Nginx 的并发能力确实在同类型的网页服务器中 ...
- 浏览器兼容 : IE 5 到 IE 9
<!--[if IE]> <link href="ie.css" rel="stylesheet"> <![endif]--> ...
- [转帖]各个版本Windows系统中自带的.NET Framework版本
① Windows Server : Windows Server版本 自带的.NET Framework 版本 Windows Server 2022 .NET Framework 4.8 Wind ...
- [转帖]使用 Dumpling 导出数据
16 Contributors 使用数据导出工具 Dumpling,你可以把存储在 TiDB 或 MySQL 中的数据导出为 SQL 或 CSV 格式,用于逻辑全量备份.Dumpling 也支持将 ...
- [转帖]INSERT IGNORE INTO 与 INSERT INTO
INSERT IGNORE INTO 会忽略数据库中已经存在 的数据,如果数据库没有数据,就插入新的数据,如果有数据的话就跳过当前插入的这条数据.这样就可以保留数据库中已经存在数据,达到在间隙中插入数 ...
- [转帖]Tomcat部署及优化
目录 一.Tomcat简介 1 Tomcat的三大核心组件 2 Java Servlet 3 JSP全称Java Server Pages 4 Tomcat 功能组件结构 5 Tomcat 请求过程 ...