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 2019/12/19 07:14:33 UTC

[dubbo] 01/04: [Dubbo-5495] Services can't be exported for projects driven by annotation but with EnableDubbo/EnableDubboLifecycle not enabled (#5496)

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

commit 2d2341e544927244843fda934529bd8445ea99bf
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Wed Dec 18 10:44:58 2019 +0800

    [Dubbo-5495] Services can't be exported for projects driven by annotation but with EnableDubbo/EnableDubboLifecycle not enabled (#5496)
    
    Fixes #5495
---
 .../ServiceAnnotationBeanPostProcessor.java        | 11 +++-
 .../context/DubboBootstrapApplicationListener.java | 63 +++++++++++++++++++
 ...DubboLifecycleComponentApplicationListener.java | 60 +++++++-----------
 ...meExecutionApplicationContextEventListener.java | 71 ++++++++++++++++++++++
 .../DubboLifecycleComponentRegistrar.java          |  2 +
 .../beans/factory/ServiceBeanPostProcessor.java    | 37 -----------
 .../ServiceAnnotationTestConfiguration.java        |  6 --
 .../spring/context/annotation/EnableDubboTest.java |  6 --
 .../annotation/provider/ProviderConfiguration.java |  6 --
 9 files changed, 167 insertions(+), 95 deletions(-)

diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
index c96f7b9..08a0965 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.config.MethodConfig;
 import org.apache.dubbo.config.annotation.Method;
 import org.apache.dubbo.config.annotation.Service;
 import org.apache.dubbo.config.spring.ServiceBean;
+import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
 import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
 
 import org.springframework.beans.BeansException;
@@ -63,6 +64,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static com.alibaba.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans;
 import static com.alibaba.spring.util.ObjectUtils.of;
 import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
 import static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveServiceInterfaceClass;
@@ -107,6 +109,9 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
     @Override
     public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
 
+        // @since 2.7.5
+        registerBeans(registry, DubboBootstrapApplicationListener.class);
+
         Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
 
         if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
@@ -456,10 +461,10 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
     }
 
     private List convertMethodConfigs(Object methodsAnnotation) {
-        if (methodsAnnotation == null){
+        if (methodsAnnotation == null) {
             return Collections.EMPTY_LIST;
         }
-        return MethodConfig.constructMethodConfig((Method[])methodsAnnotation);
+        return MethodConfig.constructMethodConfig((Method[]) methodsAnnotation);
     }
 
     private ManagedList<RuntimeBeanReference> toRuntimeBeanReferences(String... beanNames) {
@@ -523,4 +528,4 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
         this.classLoader = classLoader;
     }
 
-}
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java
new file mode 100644
index 0000000..fd11690
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.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.context;
+
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ApplicationContextEvent;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.core.Ordered;
+
+/**
+ * The {@link ApplicationListener} for {@link DubboBootstrap}'s lifecycle when the {@link ContextRefreshedEvent}
+ * and {@link ContextClosedEvent} raised
+ *
+ * @since 2.7.5
+ */
+public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
+        implements Ordered {
+
+    private final DubboBootstrap dubboBootstrap;
+
+    public DubboBootstrapApplicationListener() {
+        this.dubboBootstrap = DubboBootstrap.getInstance();
+    }
+
+    @Override
+    public void onApplicationContextEvent(ApplicationContextEvent event) {
+        if (event instanceof ContextRefreshedEvent) {
+            onContextRefreshedEvent((ContextRefreshedEvent) event);
+        } else if (event instanceof ContextClosedEvent) {
+            onContextClosedEvent((ContextClosedEvent) event);
+        }
+    }
+
+    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
+        dubboBootstrap.start();
+    }
+
+    private void onContextClosedEvent(ContextClosedEvent event) {
+        dubboBootstrap.stop();
+    }
+
+    @Override
+    public int getOrder() {
+        return LOWEST_PRECEDENCE;
+    }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
index 61cb66d..7aad776 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
@@ -18,20 +18,18 @@ package org.apache.dubbo.config.spring.context;
 
 
 import org.apache.dubbo.common.context.Lifecycle;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.config.DubboShutdownHook;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 
 import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationEvent;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ApplicationContextEvent;
 import org.springframework.context.event.ContextClosedEvent;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.context.event.SmartApplicationListener;
 
-import java.util.Map;
+import java.util.LinkedList;
+import java.util.List;
 
+import static java.util.Collections.emptyList;
 import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors;
 
 /**
@@ -41,15 +39,12 @@ import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncl
  * @see SmartApplicationListener
  * @since 2.7.5
  */
-public class DubboLifecycleComponentApplicationListener implements ApplicationListener {
+public class DubboLifecycleComponentApplicationListener extends OneTimeExecutionApplicationContextEventListener {
 
-    @Override
-    public void onApplicationEvent(ApplicationEvent event) {
-
-        if (!supportsEvent(event)) {
-            return;
-        }
+    private List<Lifecycle> lifecycleComponents = emptyList();
 
+    @Override
+    protected void onApplicationContextEvent(ApplicationContextEvent event) {
         if (event instanceof ContextRefreshedEvent) {
             onContextRefreshedEvent((ContextRefreshedEvent) event);
         } else if (event instanceof ContextClosedEvent) {
@@ -58,40 +53,31 @@ public class DubboLifecycleComponentApplicationListener implements ApplicationLi
     }
 
     protected void onContextRefreshedEvent(ContextRefreshedEvent event) {
-        ApplicationContext context = event.getApplicationContext();
-        DubboBootstrap bootstrap = loadBootsttrapAsBean(context);
-        if (bootstrap == null) {
-            bootstrap = DubboBootstrap.getInstance();
-        }
-        bootstrap.start();
+        initLifecycleComponents(event);
+        startLifecycleComponents();
     }
 
     protected void onContextClosedEvent(ContextClosedEvent event) {
-        DubboShutdownHook.getDubboShutdownHook().doDestroy();
+        destroyLifecycleComponents();
     }
 
-    private DubboBootstrap loadBootsttrapAsBean(ApplicationContext context) {
-        Map<String, DubboBootstrap> beans = beansOfTypeIncludingAncestors(context, DubboBootstrap.class);
-        if (CollectionUtils.isNotEmptyMap(beans)) {
-            return beans.values().iterator().next();
-        }
-        return null;
+    private void initLifecycleComponents(ContextRefreshedEvent event) {
+        ApplicationContext context = event.getApplicationContext();
+        ClassLoader classLoader = context.getClassLoader();
+        lifecycleComponents = new LinkedList<>();
+        // load the Beans of Lifecycle from ApplicationContext
+        loadLifecycleComponents(lifecycleComponents, context);
     }
 
-    /**
-     * the specified {@link ApplicationEvent event} must be {@link ApplicationContextEvent} and
-     * its correlative {@link ApplicationContext} must be root
-     *
-     * @param event
-     * @return
-     */
-    private boolean supportsEvent(ApplicationEvent event) {
-        return event instanceof ApplicationContextEvent &&
-                isRootApplicationContext((ApplicationContextEvent) event);
+    private void loadLifecycleComponents(List<Lifecycle> lifecycleComponents, ApplicationContext context) {
+        lifecycleComponents.addAll(beansOfTypeIncludingAncestors(context, Lifecycle.class).values());
     }
 
+    private void startLifecycleComponents() {
+        lifecycleComponents.forEach(Lifecycle::start);
+    }
 
-    private boolean isRootApplicationContext(ApplicationContextEvent event) {
-        return event.getApplicationContext().getParent() == null;
+    private void destroyLifecycleComponents() {
+        lifecycleComponents.forEach(Lifecycle::destroy);
     }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/OneTimeExecutionApplicationContextEventListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/OneTimeExecutionApplicationContextEventListener.java
new file mode 100644
index 0000000..569a67e
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/OneTimeExecutionApplicationContextEventListener.java
@@ -0,0 +1,71 @@
+/*
+ * 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.context;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ApplicationContextEvent;
+
+import java.util.Objects;
+
+/**
+ * The abstract class {@link ApplicationListener} for {@link ApplicationContextEvent} guarantees just one-time execution
+ * and prevents the event propagation in the hierarchical {@link ApplicationContext ApplicationContexts}
+ *
+ * @since 2.7.5
+ */
+abstract class OneTimeExecutionApplicationContextEventListener implements ApplicationListener, ApplicationContextAware {
+
+    private ApplicationContext applicationContext;
+
+    public final void onApplicationEvent(ApplicationEvent event) {
+        if (isOriginalEventSource(event) && event instanceof ApplicationContextEvent) {
+            onApplicationContextEvent((ApplicationContextEvent) event);
+        }
+    }
+
+    /**
+     * The subclass overrides this method to handle {@link ApplicationContextEvent}
+     *
+     * @param event {@link ApplicationContextEvent}
+     */
+    protected abstract void onApplicationContextEvent(ApplicationContextEvent event);
+
+    /**
+     * Is original {@link ApplicationContext} as the event source
+     *
+     * @param event {@link ApplicationEvent}
+     * @return
+     */
+    private boolean isOriginalEventSource(ApplicationEvent event) {
+        return (applicationContext == null) // Current ApplicationListener is not a Spring Bean, just was added
+                // into Spring's ConfigurableApplicationContext
+                || Objects.equals(applicationContext, event.getSource());
+    }
+
+    @Override
+    public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+
+    public ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboLifecycleComponentRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboLifecycleComponentRegistrar.java
index c192c8d..20fd1a9 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboLifecycleComponentRegistrar.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboLifecycleComponentRegistrar.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.config.spring.context.annotation;
 
 import org.apache.dubbo.common.context.Lifecycle;
+import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
 import org.apache.dubbo.config.spring.context.DubboLifecycleComponentApplicationListener;
 
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -35,5 +36,6 @@ public class DubboLifecycleComponentRegistrar implements ImportBeanDefinitionReg
     @Override
     public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
         registerBeans(registry, DubboLifecycleComponentApplicationListener.class);
+        registerBeans(registry, DubboBootstrapApplicationListener.class);
     }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/ServiceBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/ServiceBeanPostProcessor.java
deleted file mode 100644
index 52c7500..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/ServiceBeanPostProcessor.java
+++ /dev/null
@@ -1,37 +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;
-
-import org.apache.dubbo.config.spring.ServiceBean;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
-
-public class ServiceBeanPostProcessor implements BeanPostProcessor {
-    @Override
-    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        return bean;
-    }
-
-    @Override
-    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
-        if (bean instanceof ServiceBean) {
-            ((ServiceBean) bean).export();
-        }
-        return bean;
-    }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java
index daa95aa..7a206db 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java
@@ -21,7 +21,6 @@ import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.annotation.Service;
-import org.apache.dubbo.config.spring.beans.factory.ServiceBeanPostProcessor;
 
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
@@ -86,11 +85,6 @@ public class ServiceAnnotationTestConfiguration {
         return protocolConfig;
     }
 
-    @Bean
-    public ServiceBeanPostProcessor serviceBeanPostProcessor() {
-        return new ServiceBeanPostProcessor();
-    }
-
     @Primary
     @Bean
     public PlatformTransactionManager platformTransactionManager() {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
index 54660b7..42fadfc 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
@@ -18,7 +18,6 @@ package org.apache.dubbo.config.spring.context.annotation;
 
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.spring.api.DemoService;
-import org.apache.dubbo.config.spring.beans.factory.ServiceBeanPostProcessor;
 import org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration;
 import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -152,11 +151,6 @@ public class EnableDubboTest {
     @EnableTransactionManagement
     public static class TestProviderConfiguration {
 
-        @Bean
-        public ServiceBeanPostProcessor serviceBeanPostProcessor() {
-            return new ServiceBeanPostProcessor();
-        }
-
         @Primary
         @Bean
         public PlatformTransactionManager platformTransactionManager() {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java
index b31e670..d168af8 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java
@@ -19,7 +19,6 @@ package org.apache.dubbo.config.spring.context.annotation.provider;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.spring.beans.factory.ServiceBeanPostProcessor;
 import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
 
 import org.springframework.context.annotation.Bean;
@@ -82,11 +81,6 @@ public class ProviderConfiguration {
         return protocolConfig;
     }
 
-    @Bean
-    public ServiceBeanPostProcessor serviceBeanPostProcessor() {
-        return new ServiceBeanPostProcessor();
-    }
-
     @Primary
     @Bean
     public PlatformTransactionManager platformTransactionManager() {