You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/12/15 06:26:01 UTC
[dubbo] branch master updated: Fix DubboConfigEarlyInitializationPostProcessor registered twice in Spring Framework (#9397)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/master by this push:
new 9cfb1ae Fix DubboConfigEarlyInitializationPostProcessor registered twice in Spring Framework (#9397)
9cfb1ae is described below
commit 9cfb1ae7ac91800f38d147b816c4e0d5ccff75e7
Author: gitchenjh <84...@qq.com>
AuthorDate: Wed Dec 15 14:25:17 2021 +0800
Fix DubboConfigEarlyInitializationPostProcessor registered twice in Spring Framework (#9397)
fixes #9370
---
...ubboConfigEarlyInitializationPostProcessor.java | 127 -------------------
.../DubboConfigEarlyRegistrationPostProcessor.java | 139 +++++++++++++++++++++
.../dubbo/config/spring/util/DubboBeanUtils.java | 11 +-
.../config/DubboConfigEarlyInitializationTest.java | 63 ++++++++++
.../spring/dubbo-config-early-initialization.xml | 33 +++++
5 files changed, 241 insertions(+), 132 deletions(-)
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationPostProcessor.java
deleted file mode 100644
index 7ec87ca..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationPostProcessor.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.config.spring.beans.factory.config;
-
-import org.apache.dubbo.config.AbstractConfig;
-import org.apache.dubbo.config.context.ConfigManager;
-
-import com.alibaba.spring.beans.factory.config.GenericBeanPostProcessorAdapter;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
-import org.springframework.core.PriorityOrdered;
-
-import javax.annotation.PostConstruct;
-
-/**
- * Generally, {@link AbstractConfig Dubbo Config} Bean will be added into {@link ConfigManager} on the bean initialization
- * life cycle through {@link CommonAnnotationBeanPostProcessor} executing the callback of
- * {@link PostConstruct @PostConstruct}. However, the instantiation and initialization of
- * {@link AbstractConfig Dubbo Config} Bean could be too early before {@link CommonAnnotationBeanPostProcessor}, e.g,
- * execution, thus it's required to register the current instance as a {@link BeanPostProcessor} into
- * {@link DefaultListableBeanFactory the BeanFatory} using {@link BeanDefinitionRegistryPostProcessor} as early as
- * possible.
- *
- * @see GenericBeanPostProcessorAdapter
- * @since 2.7.9
- */
-public class DubboConfigEarlyInitializationPostProcessor extends GenericBeanPostProcessorAdapter<AbstractConfig>
- implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
-
- private static final Log logger = LogFactory.getLog(DubboConfigEarlyInitializationPostProcessor.class.getName());
-
- public static final String BEAN_NAME = "dubboConfigEarlyInitializationPostProcessor";
-
- private DefaultListableBeanFactory beanFactory;
-
- @Override
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
- this.beanFactory = unwrap(registry);
- initBeanFactory();
- }
-
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
- if (beanFactory == null) { // try again if postProcessBeanDefinitionRegistry method does not effect.
- this.beanFactory = unwrap(beanFactory);
- initBeanFactory();
- }
- }
-
- protected void processBeforeInitialization(AbstractConfig config, String beanName) throws BeansException {
-
- if (this.beanFactory == null) {
- if (logger.isErrorEnabled()) {
- logger.error("Current Processor is not running in Spring container, next action will be skipped!");
- }
- return;
- }
-
- // If CommonAnnotationBeanPostProcessor is already registered, the method addIntoConfigManager()
- // will be invoked in Bean life cycle.
- if (!hasRegisteredCommonAnnotationBeanPostProcessor()) {
- if (logger.isWarnEnabled()) {
- logger.warn("CommonAnnotationBeanPostProcessor is not registered yet, " +
- "the method addIntoConfigManager() will be invoked directly");
- }
- config.addIntoConfigManager();
- }
- }
-
- private DefaultListableBeanFactory unwrap(Object registry) {
- if (registry instanceof DefaultListableBeanFactory) {
- return (DefaultListableBeanFactory) registry;
- }
- return null;
- }
-
- private void initBeanFactory() {
- if (beanFactory != null) {
- // Register itself
- if (logger.isInfoEnabled()) {
- logger.info("BeanFactory is about to be initialized, trying to resolve the Dubbo Config Beans early " +
- "initialization");
- }
- beanFactory.addBeanPostProcessor(this);
- }
- }
-
- /**
- * {@link DefaultListableBeanFactory} has registered {@link CommonAnnotationBeanPostProcessor} or not?
- *
- * @return if registered, return <code>true</code>, or <code>false</code>
- */
- private boolean hasRegisteredCommonAnnotationBeanPostProcessor() {
- for (BeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessors()) {
- if (CommonAnnotationBeanPostProcessor.class.equals(beanPostProcessor.getClass())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public int getOrder() {
- return HIGHEST_PRECEDENCE;
- }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyRegistrationPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyRegistrationPostProcessor.java
new file mode 100644
index 0000000..4ce9e3e
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyRegistrationPostProcessor.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.spring.beans.factory.config;
+
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+
+import com.alibaba.spring.beans.factory.config.GenericBeanPostProcessorAdapter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.core.PriorityOrdered;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * Generally, {@link AbstractConfig Dubbo Config} Bean will be added into {@link ConfigManager} on the bean initialization
+ * life cycle through {@link CommonAnnotationBeanPostProcessor} executing the callback of
+ * {@link PostConstruct @PostConstruct}. However, the instantiation and initialization of
+ * {@link AbstractConfig Dubbo Config} Bean could be too early before {@link CommonAnnotationBeanPostProcessor}, e.g,
+ * execution, thus it's required to register the {@link DubboConfigEarlyInitializationPostProcessor
+ * DubboConfigEarlyInitializationPostProcessor} instance as a {@link BeanPostProcessor} into
+ * {@link DefaultListableBeanFactory the BeanFatory} using {@link BeanDefinitionRegistryPostProcessor} as early as
+ * possible.
+ *
+ * @author <a href="mailto:842761733@qq.com">chenjh</a>
+ * @see DubboConfigEarlyInitializationPostProcessor
+ * @since 2.7.15
+ */
+public class DubboConfigEarlyRegistrationPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
+
+ public static final String BEAN_NAME = "dubboConfigEarlyRegistrationPostProcessor";
+
+ private static final Log logger = LogFactory.getLog(DubboConfigEarlyRegistrationPostProcessor.class.getName());
+
+ private DefaultListableBeanFactory beanFactory;
+
+ private DubboConfigEarlyInitializationPostProcessor configEarlyInitializationPostProcessor =
+ new DubboConfigEarlyInitializationPostProcessor();
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+ this.beanFactory = unwrap(registry);
+ registryConfigEarlyInitializationPostProcessor(beanFactory);
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ if (this.beanFactory == null) { // try again if postProcessBeanDefinitionRegistry method does not effect.
+ this.beanFactory = unwrap(beanFactory);
+ registryConfigEarlyInitializationPostProcessor(this.beanFactory);
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return HIGHEST_PRECEDENCE;
+ }
+
+ /**
+ * Register DubboConfigEarlyInitializationPostProcessor as BeanPostProcessor manually
+ * before {@link AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory)
+ * Spring Framework automatically register}
+ */
+ private void registryConfigEarlyInitializationPostProcessor(DefaultListableBeanFactory beanFactory) {
+ if (beanFactory != null) {
+ // Register DubboConfigEarlyInitializationPostProcessor
+ beanFactory.addBeanPostProcessor(configEarlyInitializationPostProcessor);
+ if (logger.isInfoEnabled()) {
+ logger.info("DubboConfigEarlyInitializationPostProcessor has bean registered");
+ }
+ }
+ }
+
+ private DefaultListableBeanFactory unwrap(Object registry) {
+ if (registry instanceof DefaultListableBeanFactory) {
+ return (DefaultListableBeanFactory) registry;
+ }
+ return null;
+ }
+
+ class DubboConfigEarlyInitializationPostProcessor extends GenericBeanPostProcessorAdapter<AbstractConfig> {
+
+ protected void processBeforeInitialization(AbstractConfig config, String beanName) throws BeansException {
+ if (beanFactory == null) {
+ if (logger.isErrorEnabled()) {
+ logger.error("Current Processor is not running in Spring container, next action will be skipped!");
+ }
+ return;
+ }
+
+ // If CommonAnnotationBeanPostProcessor is already registered, the method addIntoConfigManager()
+ // will be invoked in Bean life cycle.
+ if (!hasRegisteredCommonAnnotationBeanPostProcessor()) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("CommonAnnotationBeanPostProcessor is not registered yet, " +
+ "the method addIntoConfigManager() will be invoked directly");
+ }
+ config.addIntoConfigManager();
+ }
+ }
+
+ /**
+ * {@link DefaultListableBeanFactory} has registered {@link CommonAnnotationBeanPostProcessor} or not?
+ *
+ * @return if registered, return <code>true</code>, or <code>false</code>
+ */
+ private boolean hasRegisteredCommonAnnotationBeanPostProcessor() {
+ for (BeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessors()) {
+ if (CommonAnnotationBeanPostProcessor.class.equals(beanPostProcessor.getClass())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
index e6d7d9d..5d1ba6a 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
@@ -21,10 +21,11 @@ import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;
-import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigEarlyInitializationPostProcessor;
+import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigEarlyRegistrationPostProcessor;
import org.apache.dubbo.config.spring.context.DubboApplicationListenerRegistrar;
import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
import org.apache.dubbo.config.spring.context.DubboLifecycleComponentApplicationListener;
+
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
@@ -89,9 +90,9 @@ public abstract class DubboBeanUtils {
registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
- // Since 2.7.9 Register DubboConfigEarlyInitializationPostProcessor as an infrastructure Bean
- registerInfrastructureBean(registry, DubboConfigEarlyInitializationPostProcessor.BEAN_NAME,
- DubboConfigEarlyInitializationPostProcessor.class);
+ // Since 2.7.15 Register DubboConfigEarlyRegistrationPostProcessor as an infrastructure Bean
+ registerInfrastructureBean(registry, DubboConfigEarlyRegistrationPostProcessor.BEAN_NAME,
+ DubboConfigEarlyRegistrationPostProcessor.class);
}
/**
@@ -126,7 +127,7 @@ public abstract class DubboBeanUtils {
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, beanType, true, false);
if (beanNames == null || beanNames.length == 0) {
return null;
- } else if (beanNames.length > 1){
+ } else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(beanType, Arrays.asList(beanNames));
}
return (T) beanFactory.getBean(beanNames[0]);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationTest.java
new file mode 100644
index 0000000..08e68ed
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigEarlyInitializationTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.spring.beans.factory.config;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = DubboConfigEarlyInitializationTest.class)
+@ImportResource(locations = "classpath:/META-INF/spring/dubbo-config-early-initialization.xml")
+@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
+public class DubboConfigEarlyInitializationTest {
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Test
+ public void testDubboConfigEarlyInitializationPostProcessor() {
+ assertTrue(applicationContext instanceof GenericApplicationContext);
+ ConfigurableListableBeanFactory clBeanFactory = ((GenericApplicationContext) applicationContext).getBeanFactory();
+ assertTrue(clBeanFactory instanceof DefaultListableBeanFactory);
+ DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) clBeanFactory;
+ List<BeanPostProcessor> beanPostProcessorList = beanFactory.getBeanPostProcessors();
+ assertEquals(beanFactory.getBeanPostProcessorCount(), beanPostProcessorList.size());
+ boolean containsDubboConfigEarlyInitializationPostProcessor = false;
+ for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
+ if (beanPostProcessor instanceof DubboConfigEarlyRegistrationPostProcessor.DubboConfigEarlyInitializationPostProcessor) {
+ containsDubboConfigEarlyInitializationPostProcessor = true;
+ break;
+ }
+ }
+ assertTrue(containsDubboConfigEarlyInitializationPostProcessor);
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-config-early-initialization.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-config-early-initialization.xml
new file mode 100644
index 0000000..8d72ae9
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-config-early-initialization.xml
@@ -0,0 +1,33 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+ xmlns="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
+ ">
+
+ <!-- current application configuration -->
+ <dubbo:application id="application" name="demo-provider"/>
+
+ <!-- registry center configuration -->
+ <dubbo:registry id="registry" address="N/A"/>
+
+ <!-- protocol configuration -->
+ <dubbo:protocol name="dubbo" port="-1"/>
+
+</beans>
\ No newline at end of file