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 7ec87cafbac..00000000000 --- 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 - 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 true, or false - */ - 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 00000000000..4ce9e3e0ef0 --- /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 chenjh + * @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 { + + 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 true, or false + */ + 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 e6d7d9d2142..5d1ba6acaeb 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.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 static void registerCommonBeans(BeanDefinitionRegistry registry) { 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 @@ private static T getOptionalBeanByType(ListableBeanFactory beanFactory, Clas 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 00000000000..08e68ed9ab4 --- /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 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 00000000000..8d72ae96123 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-config-early-initialization.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + \ No newline at end of file