Skip to content

Commit 9cfb1ae

Browse files
authored
Fix DubboConfigEarlyInitializationPostProcessor registered twice in Spring Framework (#9397)
fixes #9370
1 parent 7cb6bff commit 9cfb1ae

5 files changed

Lines changed: 241 additions & 132 deletions

File tree

dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationPostProcessor.java

Lines changed: 0 additions & 127 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.dubbo.config.spring.beans.factory.config;
18+
19+
import org.apache.dubbo.config.AbstractConfig;
20+
import org.apache.dubbo.config.context.ConfigManager;
21+
22+
import com.alibaba.spring.beans.factory.config.GenericBeanPostProcessorAdapter;
23+
import org.apache.commons.logging.Log;
24+
import org.apache.commons.logging.LogFactory;
25+
import org.springframework.beans.BeansException;
26+
import org.springframework.beans.factory.config.BeanPostProcessor;
27+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
28+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
29+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
30+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
31+
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
32+
import org.springframework.context.support.AbstractApplicationContext;
33+
import org.springframework.core.PriorityOrdered;
34+
35+
import javax.annotation.PostConstruct;
36+
37+
/**
38+
* Generally, {@link AbstractConfig Dubbo Config} Bean will be added into {@link ConfigManager} on the bean initialization
39+
* life cycle through {@link CommonAnnotationBeanPostProcessor} executing the callback of
40+
* {@link PostConstruct @PostConstruct}. However, the instantiation and initialization of
41+
* {@link AbstractConfig Dubbo Config} Bean could be too early before {@link CommonAnnotationBeanPostProcessor}, e.g,
42+
* execution, thus it's required to register the {@link DubboConfigEarlyInitializationPostProcessor
43+
* DubboConfigEarlyInitializationPostProcessor} instance as a {@link BeanPostProcessor} into
44+
* {@link DefaultListableBeanFactory the BeanFatory} using {@link BeanDefinitionRegistryPostProcessor} as early as
45+
* possible.
46+
*
47+
* @author <a href="mailto:842761733@qq.com">chenjh</a>
48+
* @see DubboConfigEarlyInitializationPostProcessor
49+
* @since 2.7.15
50+
*/
51+
public class DubboConfigEarlyRegistrationPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
52+
53+
public static final String BEAN_NAME = "dubboConfigEarlyRegistrationPostProcessor";
54+
55+
private static final Log logger = LogFactory.getLog(DubboConfigEarlyRegistrationPostProcessor.class.getName());
56+
57+
private DefaultListableBeanFactory beanFactory;
58+
59+
private DubboConfigEarlyInitializationPostProcessor configEarlyInitializationPostProcessor =
60+
new DubboConfigEarlyInitializationPostProcessor();
61+
62+
@Override
63+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
64+
this.beanFactory = unwrap(registry);
65+
registryConfigEarlyInitializationPostProcessor(beanFactory);
66+
}
67+
68+
@Override
69+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
70+
if (this.beanFactory == null) { // try again if postProcessBeanDefinitionRegistry method does not effect.
71+
this.beanFactory = unwrap(beanFactory);
72+
registryConfigEarlyInitializationPostProcessor(this.beanFactory);
73+
}
74+
}
75+
76+
@Override
77+
public int getOrder() {
78+
return HIGHEST_PRECEDENCE;
79+
}
80+
81+
/**
82+
* Register DubboConfigEarlyInitializationPostProcessor as BeanPostProcessor manually
83+
* before {@link AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory)
84+
* Spring Framework automatically register}
85+
*/
86+
private void registryConfigEarlyInitializationPostProcessor(DefaultListableBeanFactory beanFactory) {
87+
if (beanFactory != null) {
88+
// Register DubboConfigEarlyInitializationPostProcessor
89+
beanFactory.addBeanPostProcessor(configEarlyInitializationPostProcessor);
90+
if (logger.isInfoEnabled()) {
91+
logger.info("DubboConfigEarlyInitializationPostProcessor has bean registered");
92+
}
93+
}
94+
}
95+
96+
private DefaultListableBeanFactory unwrap(Object registry) {
97+
if (registry instanceof DefaultListableBeanFactory) {
98+
return (DefaultListableBeanFactory) registry;
99+
}
100+
return null;
101+
}
102+
103+
class DubboConfigEarlyInitializationPostProcessor extends GenericBeanPostProcessorAdapter<AbstractConfig> {
104+
105+
protected void processBeforeInitialization(AbstractConfig config, String beanName) throws BeansException {
106+
if (beanFactory == null) {
107+
if (logger.isErrorEnabled()) {
108+
logger.error("Current Processor is not running in Spring container, next action will be skipped!");
109+
}
110+
return;
111+
}
112+
113+
// If CommonAnnotationBeanPostProcessor is already registered, the method addIntoConfigManager()
114+
// will be invoked in Bean life cycle.
115+
if (!hasRegisteredCommonAnnotationBeanPostProcessor()) {
116+
if (logger.isWarnEnabled()) {
117+
logger.warn("CommonAnnotationBeanPostProcessor is not registered yet, " +
118+
"the method addIntoConfigManager() will be invoked directly");
119+
}
120+
config.addIntoConfigManager();
121+
}
122+
}
123+
124+
/**
125+
* {@link DefaultListableBeanFactory} has registered {@link CommonAnnotationBeanPostProcessor} or not?
126+
*
127+
* @return if registered, return <code>true</code>, or <code>false</code>
128+
*/
129+
private boolean hasRegisteredCommonAnnotationBeanPostProcessor() {
130+
for (BeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessors()) {
131+
if (CommonAnnotationBeanPostProcessor.class.equals(beanPostProcessor.getClass())) {
132+
return true;
133+
}
134+
}
135+
return false;
136+
}
137+
138+
}
139+
}

dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
2222
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
2323
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;
24-
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigEarlyInitializationPostProcessor;
24+
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigEarlyRegistrationPostProcessor;
2525
import org.apache.dubbo.config.spring.context.DubboApplicationListenerRegistrar;
2626
import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
2727
import org.apache.dubbo.config.spring.context.DubboLifecycleComponentApplicationListener;
28+
2829
import org.springframework.beans.BeansException;
2930
import org.springframework.beans.factory.BeanFactoryUtils;
3031
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
@@ -89,9 +90,9 @@ public static void registerCommonBeans(BeanDefinitionRegistry registry) {
8990
registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
9091
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
9192

92-
// Since 2.7.9 Register DubboConfigEarlyInitializationPostProcessor as an infrastructure Bean
93-
registerInfrastructureBean(registry, DubboConfigEarlyInitializationPostProcessor.BEAN_NAME,
94-
DubboConfigEarlyInitializationPostProcessor.class);
93+
// Since 2.7.15 Register DubboConfigEarlyRegistrationPostProcessor as an infrastructure Bean
94+
registerInfrastructureBean(registry, DubboConfigEarlyRegistrationPostProcessor.BEAN_NAME,
95+
DubboConfigEarlyRegistrationPostProcessor.class);
9596
}
9697

9798
/**
@@ -126,7 +127,7 @@ private static <T> T getOptionalBeanByType(ListableBeanFactory beanFactory, Clas
126127
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, beanType, true, false);
127128
if (beanNames == null || beanNames.length == 0) {
128129
return null;
129-
} else if (beanNames.length > 1){
130+
} else if (beanNames.length > 1) {
130131
throw new NoUniqueBeanDefinitionException(beanType, Arrays.asList(beanNames));
131132
}
132133
return (T) beanFactory.getBean(beanNames[0]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.dubbo.config.spring.beans.factory.config;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.beans.factory.config.BeanPostProcessor;
23+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
24+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
25+
import org.springframework.context.ApplicationContext;
26+
import org.springframework.context.annotation.ImportResource;
27+
import org.springframework.context.support.GenericApplicationContext;
28+
import org.springframework.test.annotation.DirtiesContext;
29+
import org.springframework.test.context.ContextConfiguration;
30+
import org.springframework.test.context.junit.jupiter.SpringExtension;
31+
32+
import java.util.List;
33+
34+
import static org.junit.jupiter.api.Assertions.assertEquals;
35+
import static org.junit.jupiter.api.Assertions.assertTrue;
36+
37+
@ExtendWith(SpringExtension.class)
38+
@ContextConfiguration(classes = DubboConfigEarlyInitializationTest.class)
39+
@ImportResource(locations = "classpath:/META-INF/spring/dubbo-config-early-initialization.xml")
40+
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
41+
public class DubboConfigEarlyInitializationTest {
42+
43+
@Autowired
44+
private ApplicationContext applicationContext;
45+
46+
@Test
47+
public void testDubboConfigEarlyInitializationPostProcessor() {
48+
assertTrue(applicationContext instanceof GenericApplicationContext);
49+
ConfigurableListableBeanFactory clBeanFactory = ((GenericApplicationContext) applicationContext).getBeanFactory();
50+
assertTrue(clBeanFactory instanceof DefaultListableBeanFactory);
51+
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) clBeanFactory;
52+
List<BeanPostProcessor> beanPostProcessorList = beanFactory.getBeanPostProcessors();
53+
assertEquals(beanFactory.getBeanPostProcessorCount(), beanPostProcessorList.size());
54+
boolean containsDubboConfigEarlyInitializationPostProcessor = false;
55+
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
56+
if (beanPostProcessor instanceof DubboConfigEarlyRegistrationPostProcessor.DubboConfigEarlyInitializationPostProcessor) {
57+
containsDubboConfigEarlyInitializationPostProcessor = true;
58+
break;
59+
}
60+
}
61+
assertTrue(containsDubboConfigEarlyInitializationPostProcessor);
62+
}
63+
}

0 commit comments

Comments
 (0)