= = =

Fell into the Spring @Configuration pit, causing aliyun RocketMq consumer state (two clients out of the same process) to be abnormal

1 Crime Scene

The repetition code

@Configuration public class BeanConflict { @Bean("MyAtomic1") public MyAtomic getMyAtomic(@Value("${OONN}") String oonn){ System.out.println(oonn); System.out.println("--------first--------"); return new MyAtomic(); } @Bean("MyAtomic") public MyAtomic getMyAtomic(){ System.out.println("---------------------"); System.out.println("--------second--------"); return new MyAtomic(); }}Copy the code

2 Source code analysis based on Spring-Context 5.1.6

refresh

— — — — — > org. Springframework. Context. Support. AbstractApplicationContext# invokeBeanFactoryPostProcessors / / Spring Bean (definition)

/ / traverse factory post-processor org. Springframework. Beans. Factory. Config. The spring BeanFactoryPostProcessor interface implementation class The purpose is to modify the internal bean factory

// This is the configuration class

— — — — — > org. Springframework. Context. The annotation. ConfigurationClassPostProcessor / / Spring Bean ConfigurationClass post-processor

// The simplest project has 80-90 @Configuration classes to put into a LinkedHashSet named configClasses

// Parse one by one to generate Spring beans ====>// Class level

—->org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationCl ass

// Load Spring beans according to BeanMethod

// Internally parse one by one to generate Spring beans ====>// Method level

—–>org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

// If the beanName is the same, the override judgment will be made.

—->org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#isOverriddenByExistingDefinition

/ / often produce org. Springframework. Context. The annotation. ConfigurationClassBeanDefinitionReader. ConfigurationClassBeanDefinition Type Spring Bean and into the org. Springframework. Beans. Factory. Support. DefaultListableBeanFactory# beanDefinitionMap, there will be at this time

—->// Cannot modify startup-time collection elements anymore (for stable iteration)

—->org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

—->synchronized (this.beanDefinitionMap) { … } synchronous execution

// If multiple beanmethods are repeated for a class

// loop –> Internal parsing to generate Spring beans ====>// Method level

—–>org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

—->org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationCl ass

// loop –> parse one by one to generate Spring beans ====>//class level

The following figure

Different methods for

Same method name

// After refresh, the other processing finally comes to bean instantiation, property setting, and initialization

— — — — — > org. Springframework. Beans. Factory. Support. DefaultListableBeanFactory# preInstantiateSingletons / / instantiate all the Spring Bean

— — — — > org. Springframework. Beans. Factory. Support. AbstractAutowireCapableBeanFactory# createBeanInstance / / 1159 rows A fetching of a factory method is performed

// The same is true for MyAtomic2 Spring Bean

// We decided to use factory methods to instantiate beans

— — — — > org. Springframework. Beans. Factory. Support. ConstructorResolver# instantiateUsingFactoryMethod / / match specific method

// How does this match? Choose this factory method if it represents the closest match.

// The algorithm explains how to find the nearest (smallest) method in either lenient or strict mode

/ / and the above said list is org. Springframework. Beans. Factory. Support. ConstructorResolver# getCandidateMethods decided the Arraylist

// beanName MyAtomic2 MyAtomic1 executes the same reflection method!!

// The result is to invoke the same logic to instantiate the bean—–> Same mother!!

// On the line

—–> Object result = factoryMethod.invoke(factoryBean, args); // Notice that the first parameter factoryBean is a CGLIB proxy class

—–>callback Do weave (such as parameters depend on access to such as the first parameter @ Value) – > org. Springframework. Context. The annotation. ConfigurationClassEnhancer. BeanMethodInterceptor# in tercept

— — — — — > repeat client build logic, so the two of the same subscription. Com aliyun. Openservices. Ons. API. Order. OrderConsumer came out! Two clients went to the same subscription! topic

3 summary

Be sure to distinguish method names for @Configuration + @bean annotations, because Spring Bean instantiations use factory methods, and reflection (+AOP) is used to generate Bean instances. If method differentiation is too low, it’s a problem!!

So for beans like the rocketMq client, be sure to distinguish method names, and Copy Code must rename method names!