You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by me...@apache.org on 2020/02/07 04:19:54 UTC
[dubbo] branch master updated: Polish /apache/dubbo#5446 : With
@Reference, Aop does not work (#5717)
This is an automated email from the ASF dual-hosted git repository.
mercyblitz 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 95bd350 Polish /apache/dubbo#5446 : With @Reference, Aop does not work (#5717)
95bd350 is described below
commit 95bd350cae95c0f738eade5ba78ad9827586135d
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Fri Feb 7 12:19:35 2020 +0800
Polish /apache/dubbo#5446 : With @Reference, Aop does not work (#5717)
* Polish /apache/dubbo#5446 : With @Reference, Aop does not work
* Polish /apache/dubbo#5718 : [Infrastructure] Uprade com.alibaba.spring:spring-context-support 1.0.6
* Polish /apache/dubbo#5446 : With @Reference, Aop does not work
---
dubbo-config/dubbo-config-spring/pom.xml | 7 +
.../ReferenceAnnotationBeanPostProcessor.java | 147 +++++++++++++--------
.../ReferenceAnnotationBeanPostProcessorTest.java | 37 ++++--
dubbo-dependencies-bom/pom.xml | 2 +-
4 files changed, 127 insertions(+), 66 deletions(-)
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index e88fc2d..74cc929 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -57,6 +57,13 @@
<artifactId>spring-context-support</artifactId>
</dependency>
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-default</artifactId>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
index e3f23ec..3fea6ec 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
@@ -30,7 +30,6 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -57,7 +56,7 @@ import static org.springframework.util.StringUtils.hasText;
* @since 2.5.7
*/
public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor implements
- ApplicationContextAware, ApplicationListener {
+ ApplicationContextAware, ApplicationListener<ServiceBeanExportedEvent> {
/**
* The bean name of {@link ReferenceAnnotationBeanPostProcessor}
@@ -72,15 +71,15 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
- private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache =
- new ConcurrentHashMap<>(CACHE_SIZE);
-
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
+ private final ConcurrentMap<String, ReferencedBeanInvocationHandler> referencedBeanInvocationHandlersCache =
+ new ConcurrentHashMap<>();
+
private ApplicationContext applicationContext;
/**
@@ -135,11 +134,13 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
- registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
+ boolean localServiceBean = isLocalServiceBean(referencedBeanName, referenceBean, attributes);
+
+ registerReferenceBean(referencedBeanName, referenceBean, attributes, localServiceBean, injectedType);
cacheInjectedReferenceBean(referenceBean, injectedElement);
- return getOrCreateProxy(referencedBeanName, referenceBeanName, attributes, injectedType);
+ return getOrCreateProxy(referencedBeanName, referenceBean, localServiceBean, injectedType);
}
/**
@@ -148,18 +149,19 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
* @param referencedBeanName The name of bean that annotated Dubbo's {@link Service @Service} in the Spring {@link ApplicationContext}
* @param referenceBean the instance of {@link ReferenceBean} is about to register into the Spring {@link ApplicationContext}
* @param attributes the {@link AnnotationAttributes attributes} of {@link Reference @Reference}
+ * @param localServiceBean Is Local Service bean or not
* @param interfaceClass the {@link Class class} of Service interface
* @since 2.7.3
*/
private void registerReferenceBean(String referencedBeanName, ReferenceBean referenceBean,
AnnotationAttributes attributes,
- Class<?> interfaceClass) {
+ boolean localServiceBean, Class<?> interfaceClass) {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
String beanName = getReferenceBeanName(attributes, interfaceClass);
- if (existsServiceBean(referencedBeanName)) { // If @Service bean is local one
+ if (localServiceBean) { // If @Service bean is local one
/**
* Get the @Service's BeanDefinition from {@link BeanFactory}
* Refer to {@link ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition}
@@ -223,63 +225,108 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
return beanNameBuilder.toString();
}
+ /**
+ * Is Local Service bean or not?
+ *
+ * @param referencedBeanName the bean name to the referenced bean
+ * @return If the target referenced bean is existed, return <code>true</code>, or <code>false</code>
+ * @since 2.7.6
+ */
+ private boolean isLocalServiceBean(String referencedBeanName, ReferenceBean referenceBean, AnnotationAttributes attributes) {
+ return existsServiceBean(referencedBeanName) && !isRemoteReferenceBean(referenceBean, attributes);
+ }
+
+ /**
+ * Check the {@link ServiceBean} is exited or not
+ *
+ * @param referencedBeanName the bean name to the referenced bean
+ * @return if exists, return <code>true</code>, or <code>false</code>
+ * @revised 2.7.6
+ */
private boolean existsServiceBean(String referencedBeanName) {
- return applicationContext.containsBean(referencedBeanName);
+ return applicationContext.containsBean(referencedBeanName) &&
+ applicationContext.isTypeMatch(referencedBeanName, ServiceBean.class);
+
+ }
+
+ private boolean isRemoteReferenceBean(ReferenceBean referenceBean, AnnotationAttributes attributes) {
+ boolean remote = Boolean.FALSE.equals(referenceBean.isInjvm()) || Boolean.FALSE.equals(attributes.get("injvm"));
+ return remote;
}
/**
* Get or Create a proxy of {@link ReferenceBean} for the specified the type of Dubbo service interface
*
* @param referencedBeanName The name of bean that annotated Dubbo's {@link Service @Service} in the Spring {@link ApplicationContext}
- * @param referenceBeanName the bean name of {@link ReferenceBean}
- * @param attributes the {@link AnnotationAttributes attributes} of {@link Reference @Reference}
+ * @param referenceBean the instance of {@link ReferenceBean}
+ * @param localServiceBean Is Local Service bean or not
* @param serviceInterfaceType the type of Dubbo service interface
* @return non-null
* @since 2.7.4
*/
- private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, AnnotationAttributes attributes, Class<?> serviceInterfaceType) {
-
- String beanName = getReferenceBeanName(attributes, serviceInterfaceType);
+ private Object getOrCreateProxy(String referencedBeanName, ReferenceBean referenceBean, boolean localServiceBean,
+ Class<?> serviceInterfaceType) {
+ if (localServiceBean) { // If the local @Service Bean exists, build a proxy of Service
+ return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
+ newReferencedBeanInvocationHandler(referencedBeanName));
+ } else {
+ exportServiceBeanIfNecessary(referencedBeanName); // If the referenced ServiceBean exits, export it immediately
+ return referenceBean.get();
+ }
+ }
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- // Get remote or local @Service Bean
- Object bean = beanFactory.getBean(beanName);
+ private void exportServiceBeanIfNecessary(String referencedBeanName) {
if (existsServiceBean(referencedBeanName)) {
- // If the local @Service Bean exists, build a proxy of ReferenceBean
- return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
- wrapInvocationHandler(referenceBeanName, bean));
- } else {
- return bean;
+ ServiceBean serviceBean = getServiceBean(referencedBeanName);
+ if (!serviceBean.isExported()) {
+ serviceBean.export();
+ }
}
}
+ private ServiceBean getServiceBean(String referencedBeanName) {
+ return applicationContext.getBean(referencedBeanName, ServiceBean.class);
+ }
+
+ private InvocationHandler newReferencedBeanInvocationHandler(String referencedBeanName) {
+ return referencedBeanInvocationHandlersCache.computeIfAbsent(referencedBeanName,
+ ReferencedBeanInvocationHandler::new);
+ }
+
/**
- * Wrap an instance of {@link InvocationHandler} that is used to get the proxy of {@link ReferenceBean} after
- * the specified local referenced bean that annotated {@link @Service} exported.
- *
- * @param referenceBeanName the bean name of {@link ReferenceBean}
- * @param referenceBean the instance of {@link ReferenceBean}
- * @return non-null
- * @since 2.7.4
+ * The {@link InvocationHandler} class for the referenced Bean
*/
- private InvocationHandler wrapInvocationHandler(String referenceBeanName, Object referenceBean) {
- return localReferenceBeanInvocationHandlerCache.computeIfAbsent(referenceBeanName, name ->
- new ReferenceBeanInvocationHandler(referenceBean));
+ @Override
+ public void onApplicationEvent(ServiceBeanExportedEvent event) {
+ initReferencedBeanInvocationHandler(event.getServiceBean());
+ }
+
+ private void initReferencedBeanInvocationHandler(ServiceBean serviceBean) {
+ String serviceBeanName = serviceBean.getBeanName();
+ referencedBeanInvocationHandlersCache.computeIfPresent(serviceBeanName, (name, handler) -> {
+ handler.init();
+ return null;
+ });
}
- private static class ReferenceBeanInvocationHandler implements InvocationHandler {
+ private class ReferencedBeanInvocationHandler implements InvocationHandler {
+
+ private final String referencedBeanName;
private Object bean;
- private ReferenceBeanInvocationHandler(Object bean) {
- this.bean = bean;
+ private ReferencedBeanInvocationHandler(String referencedBeanName) {
+ this.referencedBeanName = referencedBeanName;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object result;
+ Object result = null;
try {
+ if (bean == null) {
+ init();
+ }
result = method.invoke(bean, args);
} catch (InvocationTargetException e) {
// re-throws the actual Exception.
@@ -287,6 +334,11 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
}
return result;
}
+
+ private void init() {
+ ServiceBean serviceBean = applicationContext.getBean(referencedBeanName, ServiceBean.class);
+ this.bean = serviceBean.getRef();
+ }
}
@Override
@@ -341,29 +393,10 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
}
@Override
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ServiceBeanExportedEvent) {
- onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
- }
- }
-
- private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
- ServiceBean serviceBean = event.getServiceBean();
- initReferenceBeanInvocationHandler(serviceBean);
- }
-
- private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
- String serviceBeanName = serviceBean.getBeanName();
- // Remove ServiceBean when it's exported
- localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
- }
-
-
- @Override
public void destroy() throws Exception {
super.destroy();
this.referenceBeanCache.clear();
- this.localReferenceBeanInvocationHandlerCache.clear();
+ this.referencedBeanInvocationHandlersCache.clear();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index c213d78..679d46d 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -23,6 +23,9 @@ import org.apache.dubbo.config.spring.api.DemoService;
import org.apache.dubbo.config.spring.api.HelloService;
import org.apache.dubbo.config.utils.ReferenceConfigCache;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +35,8 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
@@ -51,15 +56,29 @@ import static org.junit.Assert.assertTrue;
@ContextConfiguration(
classes = {
ServiceAnnotationTestConfiguration.class,
- ReferenceAnnotationBeanPostProcessorTest.class
+ ReferenceAnnotationBeanPostProcessorTest.class,
+ ReferenceAnnotationBeanPostProcessorTest.TestAspect.class
})
@TestPropertySource(properties = {
"packagesToScan = org.apache.dubbo.config.spring.context.annotation.provider",
"consumer.version = ${demo.service.version}",
"consumer.url = dubbo://127.0.0.1:12345?version=2.5.7",
})
+@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class ReferenceAnnotationBeanPostProcessorTest {
+ private static final String AOP_SUFFIX = "(based on AOP)";
+
+ @Aspect
+ @Component
+ public static class TestAspect {
+
+ @Around("execution(* org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl.*(..))")
+ public Object aroundApi(ProceedingJoinPoint pjp) throws Throwable {
+ return pjp.proceed() + AOP_SUFFIX;
+ }
+ }
+
@Bean
public TestBean testBean() {
return new TestBean();
@@ -105,27 +124,29 @@ public class ReferenceAnnotationBeanPostProcessorTest {
Assert.assertNotNull(testBean.autowiredDemoService);
Assert.assertEquals(1, demoServicesMap.size());
- Assert.assertEquals("Hello,Mercy", demoService.sayName("Mercy"));
+ String expectedResult = "Hello,Mercy" + AOP_SUFFIX;
+
+ Assert.assertEquals(expectedResult, testBean.autowiredDemoService.sayName("Mercy"));
+ Assert.assertEquals(expectedResult, demoService.sayName("Mercy"));
Assert.assertEquals("Greeting, Mercy", defaultHelloService.sayHello("Mercy"));
Assert.assertEquals("Hello, Mercy", helloServiceImpl.sayHello("Mercy"));
Assert.assertEquals("Greeting, Mercy", helloService.sayHello("Mercy"));
- Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromAncestor().sayName("Mercy"));
- Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromParent().sayName("Mercy"));
- Assert.assertEquals("Hello,Mercy", testBean.getDemoService().sayName("Mercy"));
- Assert.assertEquals("Hello,Mercy", testBean.autowiredDemoService.sayName("Mercy"));
+ Assert.assertEquals(expectedResult, testBean.getDemoServiceFromAncestor().sayName("Mercy"));
+ Assert.assertEquals(expectedResult, testBean.getDemoServiceFromParent().sayName("Mercy"));
+ Assert.assertEquals(expectedResult, testBean.getDemoService().sayName("Mercy"));
DemoService myDemoService = context.getBean("my-reference-bean", DemoService.class);
- Assert.assertEquals("Hello,Mercy", myDemoService.sayName("Mercy"));
+ Assert.assertEquals(expectedResult, myDemoService.sayName("Mercy"));
for (DemoService demoService1 : demoServicesMap.values()) {
Assert.assertEquals(myDemoService, demoService1);
- Assert.assertEquals("Hello,Mercy", demoService1.sayName("Mercy"));
+ Assert.assertEquals(expectedResult, demoService1.sayName("Mercy"));
}
}
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 261b180..5b0b323 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -145,7 +145,7 @@
<eureka.version>1.9.12</eureka.version>
<!-- Alibaba -->
- <alibaba_spring_context_support_version>1.0.5</alibaba_spring_context_support_version>
+ <alibaba_spring_context_support_version>1.0.6</alibaba_spring_context_support_version>
<jaxb_version>2.2.7</jaxb_version>
<activation_version>1.2.0</activation_version>