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