Support service annotation work with java config bean (#8011)
This commit is contained in:
parent
c1e3a01d8c
commit
f07640fc74
|
|
@ -35,7 +35,7 @@ import java.lang.annotation.Target;
|
|||
@Deprecated
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Inherited
|
||||
public @interface Service {
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@ import java.lang.reflect.AnnotatedElement;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
|
@ -479,4 +481,56 @@ public interface AnnotationUtils {
|
|||
Method method = findMethod(annotationType, attributeName);
|
||||
return (T) (method == null ? null : method.getDefaultValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter default value of Annotation type
|
||||
* @param annotationType annotation type from {@link Annotation#annotationType()}
|
||||
* @param attributes
|
||||
* @return
|
||||
*/
|
||||
static Map<String, Object> filterDefaultValues(Class<? extends Annotation> annotationType, Map<String, Object> attributes) {
|
||||
Map<String, Object> filteredAttributes = new LinkedHashMap<>(attributes.size());
|
||||
attributes.forEach((key,val) -> {
|
||||
if (!Objects.deepEquals(val, getDefaultValue(annotationType, key))) {
|
||||
filteredAttributes.put(key, val);
|
||||
}
|
||||
});
|
||||
return filteredAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter default value of Annotation type
|
||||
* @param annotation
|
||||
* @param attributes
|
||||
* @return
|
||||
*/
|
||||
static Map<String, Object> filterDefaultValues(Annotation annotation, Map<String, Object> attributes) {
|
||||
return filterDefaultValues(annotation.annotationType(), attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attributes of annotation
|
||||
* @param annotation
|
||||
* @return
|
||||
*/
|
||||
static Map<String, Object> getAttributes(Annotation annotation, boolean filterDefaultValue) {
|
||||
Class<?> annotationType = annotation.annotationType();
|
||||
Method[] methods = annotationType.getMethods();
|
||||
Map<String, Object> attributes = new LinkedHashMap<>(methods.length);
|
||||
for (Method method : methods) {
|
||||
try {
|
||||
if (method.getDeclaringClass() == Annotation.class) {
|
||||
continue;
|
||||
}
|
||||
String name = method.getName();
|
||||
Object value = method.invoke(annotation);
|
||||
if (!filterDefaultValue || !Objects.deepEquals(value, method.getDefaultValue())) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("get attribute value of annotation failed: " + method, e);
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public abstract class AbstractConfig implements Serializable {
|
|||
protected final AtomicBoolean refreshed = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Is default or not
|
||||
* Is default config or not
|
||||
*/
|
||||
protected Boolean isDefault;
|
||||
|
||||
|
|
@ -606,6 +606,36 @@ public abstract class AbstractConfig implements Serializable {
|
|||
return refreshed.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME check @Parameter(required=true) and any conditions that need to match.
|
||||
*/
|
||||
@Parameter(excluded = true, attribute = false)
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Parameter(excluded = true, attribute = false)
|
||||
public Boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
public void setDefault(Boolean isDefault) {
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link AbstractConfig instance} into {@link ConfigManager}
|
||||
* <p>
|
||||
* Current method will invoked by Spring or Java EE container automatically, or should be triggered manually.
|
||||
*
|
||||
* @see ConfigManager#addConfig(AbstractConfig)
|
||||
* @since 2.7.5
|
||||
*/
|
||||
@PostConstruct
|
||||
public void addIntoConfigManager() {
|
||||
ApplicationModel.getConfigManager().addConfig(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
|
|
@ -658,15 +688,6 @@ public abstract class AbstractConfig implements Serializable {
|
|||
return fieldNamesCache.computeIfAbsent(configClass, ReflectUtils::getAllFieldNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME check @Parameter(required=true) and any conditions that need to match.
|
||||
*/
|
||||
@Parameter(excluded = true, attribute = false)
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != this.getClass()) {
|
||||
|
|
@ -708,19 +729,6 @@ public abstract class AbstractConfig implements Serializable {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link AbstractConfig instance} into {@link ConfigManager}
|
||||
* <p>
|
||||
* Current method will invoked by Spring or Java EE container automatically, or should be triggered manually.
|
||||
*
|
||||
* @see ConfigManager#addConfig(AbstractConfig)
|
||||
* @since 2.7.5
|
||||
*/
|
||||
@PostConstruct
|
||||
public void addIntoConfigManager() {
|
||||
ApplicationModel.getConfigManager().addConfig(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 1;
|
||||
|
|
@ -748,11 +756,4 @@ public abstract class AbstractConfig implements Serializable {
|
|||
return hashCode;
|
||||
}
|
||||
|
||||
public Boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
public void setDefault(Boolean isDefault) {
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,12 +159,6 @@ public class ProviderConfig extends AbstractServiceConfig {
|
|||
this.protocols = new ArrayList<>(Arrays.asList(new ProtocolConfig(protocol)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Parameter(excluded = true)
|
||||
public Boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
@Parameter(excluded = true)
|
||||
public String getHost() {
|
||||
return host;
|
||||
|
|
|
|||
|
|
@ -27,13 +27,40 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Class-level annotation used for declaring Dubbo service
|
||||
* Class-level annotation used for declaring Dubbo service.
|
||||
* <p/>
|
||||
* <b>1. Using with java config bean:</b>
|
||||
* <p/>
|
||||
* <b>This usage is recommended</b>.<br/>
|
||||
* It is more flexible on bean methods than on implementation classes, and is more compatible with Spring.
|
||||
* <pre>
|
||||
* @Configuration
|
||||
* class ProviderConfiguration {
|
||||
*
|
||||
* @Bean
|
||||
* @DubboService(group="demo")
|
||||
* public DemoService demoServiceImpl() {
|
||||
* return new DemoServiceImpl();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <b>2. Using on implementation class of service: </b>
|
||||
* <pre>
|
||||
* @DubboService(group="demo")
|
||||
* public class DemoServiceImpl implements DemoService {
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* This usage causes the implementation class to rely on the Dubbo module.
|
||||
*
|
||||
*
|
||||
* @since 2.7.7
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Inherited
|
||||
public @interface DubboService {
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import java.lang.annotation.Target;
|
|||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Inherited
|
||||
@Deprecated
|
||||
public @interface Service {
|
||||
|
|
|
|||
|
|
@ -676,16 +676,11 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
|
|||
}
|
||||
|
||||
static <C extends AbstractConfig> Boolean isDefaultConfig(C config) {
|
||||
// If no isDefault() method, it is considered that each can be used as default
|
||||
if (!ReflectUtils.hasMethod(config.getClass(), "isDefault")) {
|
||||
return true;
|
||||
}
|
||||
Boolean isDefault = ReflectUtils.getProperty(config, "isDefault");
|
||||
return isDefault;
|
||||
return config.isDefault();
|
||||
}
|
||||
|
||||
static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
|
||||
// find isDefault() == TRUE
|
||||
// find isDefault() == true
|
||||
List<C> list = configsMap.values()
|
||||
.stream()
|
||||
.filter(c -> TRUE.equals(ConfigManager.isDefaultConfig(c)))
|
||||
|
|
@ -700,6 +695,8 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
|
|||
.filter(c -> ConfigManager.isDefaultConfig(c) == null)
|
||||
.collect(Collectors.toList());
|
||||
return list;
|
||||
|
||||
// exclude isDefault() == false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.excludedType;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotations;
|
||||
|
|
@ -41,7 +43,9 @@ import static org.apache.dubbo.common.utils.AnnotationUtils.getAllDeclaredAnnota
|
|||
import static org.apache.dubbo.common.utils.AnnotationUtils.getAllMetaAnnotations;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getAnnotation;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getAttributes;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getDeclaredAnnotations;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getDefaultValue;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getMetaAnnotations;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getValue;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent;
|
||||
|
|
@ -100,6 +104,26 @@ public class AnnotationUtilsTest {
|
|||
assertEquals(false, getAttribute(annotation, "deprecated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAttributesMap() {
|
||||
Annotation annotation = A.class.getAnnotation(Service.class);
|
||||
Map<String, Object> attributes = getAttributes(annotation, false);
|
||||
assertEquals("java.lang.CharSequence", attributes.get("interfaceName"));
|
||||
assertEquals(CharSequence.class, attributes.get("interfaceClass"));
|
||||
assertEquals("", attributes.get("group"));
|
||||
assertEquals(getDefaultValue(annotation, "export"), attributes.get("export"));
|
||||
|
||||
Map<String, Object> filteredAttributes = filterDefaultValues(annotation, attributes);
|
||||
assertEquals(2, filteredAttributes.size());
|
||||
assertEquals("java.lang.CharSequence", filteredAttributes.get("interfaceName"));
|
||||
assertEquals(CharSequence.class, filteredAttributes.get("interfaceClass"));
|
||||
assertFalse(filteredAttributes.containsKey("group"));
|
||||
assertFalse(filteredAttributes.containsKey("export"));
|
||||
|
||||
Map<String, Object> nonDefaultAttributes = getAttributes(annotation, true);
|
||||
assertEquals(nonDefaultAttributes, filteredAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue() {
|
||||
Adaptive adaptive = A.class.getAnnotation(Adaptive.class);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
|
||||
<!-- Uncomment spring_version property to check Spring 4.x compatibility -->
|
||||
<!-- <spring_version>4.3.30.RELEASE</spring_version> -->
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -31,4 +31,15 @@ public interface Constants {
|
|||
*/
|
||||
String REFERENCE_SOURCES = "referenceSources";
|
||||
|
||||
/**
|
||||
* The name of an attribute that can be
|
||||
* {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
|
||||
* {@link org.springframework.beans.factory.config.BeanDefinition} so that
|
||||
* factory beans can signal their object type when it can't be deduced from
|
||||
* the factory bean class.
|
||||
* <p/>
|
||||
* From FactoryBean.OBJECT_TYPE_ATTRIBUTE of Spring 5.2.
|
||||
*/
|
||||
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
|
|||
* @return {@link ServiceBean}'s name
|
||||
* @since 2.6.5
|
||||
*/
|
||||
@Parameter(excluded = true)
|
||||
@Parameter(excluded = true, attribute = false)
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
|
|||
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
|
||||
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
|
||||
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
|
||||
return new AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
|
||||
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
|
||||
}
|
||||
|
||||
protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
|
||||
|
|
@ -249,11 +249,11 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
|
|||
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
if (needsRefreshInjectionMetadata(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
if (needsRefreshInjectionMetadata(metadata, clazz)) {
|
||||
if (metadata != null) {
|
||||
metadata.clear(pvs);
|
||||
}
|
||||
|
|
@ -270,6 +270,11 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
|
|||
return metadata;
|
||||
}
|
||||
|
||||
// Use custom check method to compatible with Spring 4.x
|
||||
private boolean needsRefreshInjectionMetadata(AnnotatedInjectionMetadata metadata, Class<?> clazz) {
|
||||
return (metadata == null || metadata.needsRefresh(clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return order;
|
||||
|
|
@ -402,7 +407,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
|
|||
/**
|
||||
* {@link Annotation Annotated} {@link InjectionMetadata} implementation
|
||||
*/
|
||||
protected class AnnotatedInjectionMetadata extends InjectionMetadata {
|
||||
protected static class AnnotatedInjectionMetadata extends InjectionMetadata {
|
||||
|
||||
private Class<?> targetClass;
|
||||
private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements;
|
||||
|
|
@ -425,7 +430,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
|
|||
return methodElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override // since Spring 5.2.4
|
||||
protected boolean needsRefresh(Class<?> clazz) {
|
||||
if (this.targetClass == clazz) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import org.springframework.beans.BeansException;
|
|||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.InjectionMetadata;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
|
@ -47,7 +46,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
|||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
|
@ -63,6 +61,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
|
|
@ -193,8 +192,8 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
|
|||
// Extract beanClass from generic return type of java-config bean method: ReferenceBean<DemoService>
|
||||
// see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBeanFromMethod
|
||||
Class beanClass = getBeanFactory().getType(beanName);
|
||||
MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
|
||||
if (beanClass == null) {
|
||||
MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
|
||||
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName()+"#"+factoryMethodMetadata.getMethodName()+"()";
|
||||
throw new BeanCreationException("The ReferenceBean is missing necessary generic type, which returned by the @Bean method of Java-config class. " +
|
||||
"The generic type of the returned ReferenceBean must be specified as the referenced interface type, " +
|
||||
|
|
@ -203,14 +202,14 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
|
|||
|
||||
// get dubbo reference annotation attributes
|
||||
Map<String, Object> annotationAttributes = null;
|
||||
MergedAnnotations mergedAnnotations = beanDefinition.getFactoryMethodMetadata().getAnnotations();
|
||||
Class referenceAnnotationType = null;
|
||||
// try all dubbo reference annotation types
|
||||
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
|
||||
if (mergedAnnotations.isPresent(annotationType)) {
|
||||
referenceAnnotationType = annotationType;
|
||||
annotationAttributes = mergedAnnotations.get(annotationType).filterDefaultValues().asMap();
|
||||
break;
|
||||
if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
|
||||
// Since Spring 5.2
|
||||
// return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();
|
||||
// Compatible with Spring 4.x
|
||||
annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
|
||||
annotationAttributes = filterDefaultValues(annotationType, annotationAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +225,6 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
|
|||
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
|
||||
// check beanClass and reference interface class
|
||||
if (!StringUtils.isEquals(interfaceName, beanClass.getName()) && beanClass != GenericService.class) {
|
||||
MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
|
||||
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName()+"#"+factoryMethodMetadata.getMethodName()+"()";
|
||||
throw new BeanCreationException("The 'interfaceClass' or 'interfaceName' attribute value of @DubboReference annotation " +
|
||||
"is inconsistent with the generic type of the ReferenceBean returned by the bean method. " +
|
||||
|
|
@ -468,7 +466,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
|
|||
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, id+"_decorated"));
|
||||
|
||||
// signal object type since Spring 5.2
|
||||
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
|
||||
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
|
||||
|
||||
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
|
||||
logger.info("Register dubbo reference bean: "+referenceBeanName+" = "+referenceKey+" at "+member);
|
||||
|
|
|
|||
|
|
@ -16,22 +16,25 @@
|
|||
*/
|
||||
package org.apache.dubbo.config.spring.beans.factory.annotation;
|
||||
|
||||
import com.alibaba.spring.util.AnnotationUtils;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.config.Constants;
|
||||
import org.apache.dubbo.config.MethodConfig;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
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.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
|
|
@ -43,49 +46,59 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.alibaba.spring.util.BeanRegistrar.registerInfrastructureBean;
|
||||
import static com.alibaba.spring.util.ObjectUtils.of;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
|
||||
import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
|
||||
import static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveServiceInterfaceClass;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
|
||||
import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;
|
||||
import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
|
||||
import static org.springframework.util.ClassUtils.resolveClassName;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes. it's also the
|
||||
* infrastructure class of XML {@link BeanDefinitionParser} on <dubbbo:annotation />
|
||||
* A {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes and annotated bean in java config classes.
|
||||
* It's also the infrastructure class of XML {@link BeanDefinitionParser} on <dubbbo:annotation />
|
||||
*
|
||||
*
|
||||
* @see AnnotationBeanDefinitionParser
|
||||
* @see BeanDefinitionRegistryPostProcessor
|
||||
* @since 2.7.7
|
||||
*/
|
||||
public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
|
||||
ResourceLoaderAware, BeanClassLoaderAware {
|
||||
ResourceLoaderAware, BeanClassLoaderAware, ApplicationContextAware {
|
||||
|
||||
public static final String BEAN_NAME = "dubboServiceAnnotationPostProcessor";
|
||||
|
||||
private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
|
||||
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
|
||||
|
|
@ -107,6 +120,11 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private BeanDefinitionRegistry registry;
|
||||
|
||||
private ServicePackagesHolder servicePackagesHolder;
|
||||
|
||||
|
||||
public ServiceAnnotationPostProcessor(String... packagesToScan) {
|
||||
this(asList(packagesToScan));
|
||||
}
|
||||
|
|
@ -121,14 +139,12 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
|
||||
// @since 2.7.5
|
||||
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
|
||||
this.registry = registry;
|
||||
|
||||
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
|
||||
|
||||
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
|
||||
registerServiceBeans(resolvedPackagesToScan, registry);
|
||||
scanServiceBeans(resolvedPackagesToScan, registry);
|
||||
} else {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
|
||||
|
|
@ -138,27 +154,35 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
}
|
||||
|
||||
/**
|
||||
* Registers Beans whose classes was annotated {@link Service}
|
||||
* Scan and registers service beans whose classes was annotated {@link Service}
|
||||
*
|
||||
* @param packagesToScan The base packages to scan
|
||||
* @param registry {@link BeanDefinitionRegistry}
|
||||
*/
|
||||
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
|
||||
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
|
||||
|
||||
DubboClassPathBeanDefinitionScanner scanner =
|
||||
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
|
||||
|
||||
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
|
||||
|
||||
scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
|
||||
// refactor @since 2.7.7
|
||||
serviceAnnotationTypes.forEach(annotationType -> {
|
||||
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
|
||||
});
|
||||
}
|
||||
|
||||
ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
|
||||
scanner.addExcludeFilter(scanExcludeFilter);
|
||||
|
||||
for (String packageToScan : packagesToScan) {
|
||||
|
||||
// avoid duplicated scans
|
||||
if (servicePackagesHolder.isPackageScanned(packageToScan)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Ignore package who has already bean scanned: " + packageToScan);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Registers @Service Bean first
|
||||
scanner.scan(packageToScan);
|
||||
|
||||
|
|
@ -167,28 +191,27 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
|
||||
|
||||
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
|
||||
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
|
||||
serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
|
||||
}
|
||||
logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
|
||||
}
|
||||
|
||||
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
|
||||
registerServiceBean(beanDefinitionHolder, registry, scanner);
|
||||
processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
|
||||
servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " +
|
||||
beanDefinitionHolders +
|
||||
" } were scanned under package[" + packageToScan + "]");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
|
||||
+ packageToScan + "]");
|
||||
logger.warn("No class annotated by Dubbo @Service was found under package ["
|
||||
+ packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
servicePackagesHolder.addScannedPackage(packageToScan);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -270,17 +293,15 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
* @see ServiceBean
|
||||
* @see BeanDefinition
|
||||
*/
|
||||
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
|
||||
DubboClassPathBeanDefinitionScanner scanner) {
|
||||
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
|
||||
DubboClassPathBeanDefinitionScanner scanner) {
|
||||
|
||||
Class<?> beanClass = resolveClass(beanDefinitionHolder);
|
||||
|
||||
Annotation service = findServiceAnnotation(beanClass);
|
||||
|
||||
/**
|
||||
* The {@link AnnotationAttributes} of @Service annotation
|
||||
*/
|
||||
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
|
||||
// The attributes of @Service annotation
|
||||
Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
|
||||
|
||||
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
|
||||
|
||||
|
|
@ -290,26 +311,9 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
|
||||
|
||||
AbstractBeanDefinition serviceBeanDefinition =
|
||||
buildServiceBeanDefinition(beanName, service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
|
||||
buildServiceBeanDefinition(serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
|
||||
|
||||
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
|
||||
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("The BeanDefinition[" + serviceBeanDefinition +
|
||||
"] of ServiceBean has been registered with name : " + beanName);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//TODO throw exception
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
|
||||
"] of ServiceBean[ bean name : " + beanName +
|
||||
"] was be found , Did @DubboComponentScan scan to same package in many times?");
|
||||
}
|
||||
|
||||
}
|
||||
registerServiceBeanDefinition(beanName, serviceBeanDefinition, interfaceClass);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -337,10 +341,10 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
* @return ServiceBean@interfaceClassName#annotatedServiceBeanName
|
||||
* @since 2.7.3
|
||||
*/
|
||||
private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
|
||||
private String generateServiceBeanName(Map<String, Object> serviceAnnotationAttributes, Class<?> interfaceClass) {
|
||||
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
|
||||
.group(serviceAnnotationAttributes.getString("group"))
|
||||
.version(serviceAnnotationAttributes.getString("version"));
|
||||
.group((String) serviceAnnotationAttributes.get("group"))
|
||||
.version((String) serviceAnnotationAttributes.get("version"));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
@ -375,18 +379,15 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
* Build the {@link AbstractBeanDefinition Bean Definition}
|
||||
*
|
||||
*
|
||||
* @param beanName
|
||||
* @param serviceAnnotation
|
||||
* @param serviceAnnotationAttributes
|
||||
* @param interfaceClass
|
||||
* @param annotatedServiceBeanName
|
||||
* @param refServiceBeanName
|
||||
* @return
|
||||
* @since 2.7.3
|
||||
*/
|
||||
private AbstractBeanDefinition buildServiceBeanDefinition(String beanName, Annotation serviceAnnotation,
|
||||
AnnotationAttributes serviceAnnotationAttributes,
|
||||
private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,
|
||||
Class<?> interfaceClass,
|
||||
String annotatedServiceBeanName) {
|
||||
String refServiceBeanName) {
|
||||
|
||||
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
|
||||
|
||||
|
|
@ -397,16 +398,16 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
|
||||
"interface", "interfaceName", "parameters");
|
||||
|
||||
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
|
||||
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));
|
||||
|
||||
//set config id, for ConfigManager cache key
|
||||
//builder.addPropertyValue("id", beanName);
|
||||
// References "ref" property to annotated-@Service Bean
|
||||
addPropertyReference(builder, "ref", annotatedServiceBeanName);
|
||||
addPropertyReference(builder, "ref", refServiceBeanName);
|
||||
// Set interface
|
||||
builder.addPropertyValue("interface", interfaceClass.getName());
|
||||
// Convert parameters into map
|
||||
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
|
||||
builder.addPropertyValue("parameters", convertParameters((String[]) serviceAnnotationAttributes.get("parameters")));
|
||||
// Add methods parameters
|
||||
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
|
||||
if (!methodConfigs.isEmpty()) {
|
||||
|
|
@ -414,20 +415,20 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
}
|
||||
|
||||
// convert provider to providerIds
|
||||
String providerConfigId = serviceAnnotationAttributes.getString("provider");
|
||||
String providerConfigId = (String) serviceAnnotationAttributes.get("provider");
|
||||
if (StringUtils.hasText(providerConfigId)) {
|
||||
addPropertyValue(builder, "providerIds", providerConfigId);
|
||||
}
|
||||
|
||||
// Convert registry[] to registryIds
|
||||
String[] registryConfigIds = serviceAnnotationAttributes.getStringArray("registry");
|
||||
String[] registryConfigIds = (String[]) serviceAnnotationAttributes.get("registry");
|
||||
if (registryConfigIds != null && registryConfigIds.length > 0) {
|
||||
resolveStringArray(registryConfigIds);
|
||||
builder.addPropertyValue("registryIds", StringUtils.join(registryConfigIds, ','));
|
||||
}
|
||||
|
||||
// Convert protocol[] to protocolIds
|
||||
String[] protocolConfigIds = serviceAnnotationAttributes.getStringArray("protocol");
|
||||
String[] protocolConfigIds = (String[]) serviceAnnotationAttributes.get("protocol");
|
||||
if (protocolConfigIds != null && protocolConfigIds.length > 0) {
|
||||
resolveStringArray(protocolConfigIds);
|
||||
builder.addPropertyValue("protocolIds", StringUtils.join(protocolConfigIds, ','));
|
||||
|
|
@ -435,19 +436,19 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
|
||||
// TODO Could we ignore these attributes: applicatin/monitor/module ? Use global config
|
||||
// monitor reference
|
||||
String monitorConfigId = serviceAnnotationAttributes.getString("monitor");
|
||||
String monitorConfigId = (String) serviceAnnotationAttributes.get("monitor");
|
||||
if (StringUtils.hasText(monitorConfigId)) {
|
||||
addPropertyReference(builder, "monitor", monitorConfigId);
|
||||
}
|
||||
|
||||
// application reference
|
||||
String applicationConfigId = serviceAnnotationAttributes.getString("application");
|
||||
String applicationConfigId = (String) serviceAnnotationAttributes.get("application");
|
||||
if (StringUtils.hasText(applicationConfigId)) {
|
||||
addPropertyReference(builder, "application", applicationConfigId);
|
||||
}
|
||||
|
||||
// module reference
|
||||
String moduleConfigId = serviceAnnotationAttributes.getString("module");
|
||||
String moduleConfigId = (String) serviceAnnotationAttributes.get("module");
|
||||
if (StringUtils.hasText(moduleConfigId)) {
|
||||
addPropertyReference(builder, "module", moduleConfigId);
|
||||
}
|
||||
|
|
@ -501,7 +502,99 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
String[] beanNames = beanFactory.getBeanDefinitionNames();
|
||||
for (String beanName : beanNames) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);
|
||||
if (annotationAttributes != null) {
|
||||
// process @DubboService at java-config @bean method
|
||||
processAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dubbo service annotation class at java-config @bean method
|
||||
* @return return service annotation attributes map if found, or return null if not found.
|
||||
*/
|
||||
private Map<String, Object> getServiceAnnotationAttributes(BeanDefinition beanDefinition) {
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition) {
|
||||
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
|
||||
MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
|
||||
if (factoryMethodMetadata != null) {
|
||||
// try all dubbo service annotation types
|
||||
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
|
||||
if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
|
||||
// Since Spring 5.2
|
||||
// return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();
|
||||
// Compatible with Spring 4.x
|
||||
Map<String, Object> annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
|
||||
return filterDefaultValues(annotationType, annotationAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* process @DubboService at java-config @bean method
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* public class ProviderConfig {
|
||||
*
|
||||
* @Bean
|
||||
* @DubboService(group="demo", version="1.2.3")
|
||||
* public DemoService demoService() {
|
||||
* return new DemoServiceImpl();
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
* @param refServiceBeanName
|
||||
* @param refServiceBeanDefinition
|
||||
* @param attributes
|
||||
*/
|
||||
private void processAnnotatedBeanDefinition(String refServiceBeanName, AnnotatedBeanDefinition refServiceBeanDefinition, Map<String, Object> attributes) {
|
||||
|
||||
Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);
|
||||
|
||||
// get bean class from return type
|
||||
String returnTypeName = refServiceBeanDefinition.getFactoryMethodMetadata().getReturnTypeName();
|
||||
Class<?> beanClass = resolveClassName(returnTypeName, classLoader);
|
||||
|
||||
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
|
||||
|
||||
// ServiceBean Bean name
|
||||
String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
|
||||
|
||||
AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, interfaceClass, refServiceBeanName);
|
||||
|
||||
// set id
|
||||
serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);
|
||||
|
||||
registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, interfaceClass);
|
||||
}
|
||||
|
||||
private void registerServiceBeanDefinition(String serviceBeanName, AbstractBeanDefinition serviceBeanDefinition, Class<?> interfaceClass) {
|
||||
// check service bean
|
||||
if (registry.containsBeanDefinition(serviceBeanName)) {
|
||||
BeanDefinition existingDefinition = registry.getBeanDefinition(serviceBeanName);
|
||||
if (existingDefinition.equals(serviceBeanDefinition)) {
|
||||
// exist equipment bean definition
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = "Found duplicated BeanDefinition of service interface [" + interfaceClass.getName() + "] with bean name [" + serviceBeanName +
|
||||
"], existing definition [ " + existingDefinition + "], new definition [" + serviceBeanDefinition + "]";
|
||||
logger.error(msg);
|
||||
throw new BeanDefinitionStoreException(serviceBeanDefinition.getResourceDescription(), serviceBeanName, msg);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Register ServiceBean[" + serviceBeanName + "]: " + serviceBeanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -518,4 +611,28 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
|
|||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.servicePackagesHolder = applicationContext.getBean(ServicePackagesHolder.class);
|
||||
}
|
||||
|
||||
private class ScanExcludeFilter implements TypeFilter {
|
||||
|
||||
private int excludedCount;
|
||||
|
||||
@Override
|
||||
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
|
||||
String className = metadataReader.getClassMetadata().getClassName();
|
||||
boolean excluded = servicePackagesHolder.isClassScanned(className);
|
||||
if (excluded) {
|
||||
excludedCount ++;
|
||||
}
|
||||
return excluded;
|
||||
}
|
||||
|
||||
public int getExcludedCount() {
|
||||
return excludedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A temp holder for scanned packages of service.
|
||||
*/
|
||||
public class ServicePackagesHolder {
|
||||
|
||||
public static final String BEAN_NAME = "dubboServicePackagesHolder";
|
||||
|
||||
private final Set<String> scannedPackages = new HashSet<>();
|
||||
|
||||
private final Set<String> scannedClasses = new HashSet<>();
|
||||
|
||||
|
||||
public void addScannedPackage(String apackage) {
|
||||
apackage = normalizePackage(apackage);
|
||||
synchronized (scannedPackages) {
|
||||
scannedPackages.add(apackage);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPackageScanned(String packageName) {
|
||||
packageName = normalizePackage(packageName);
|
||||
synchronized (scannedPackages) {
|
||||
if (scannedPackages.contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
for (String scannedPackage : scannedPackages) {
|
||||
if (isSubPackage(packageName, scannedPackage)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addScannedClass(String className) {
|
||||
synchronized (scannedClasses) {
|
||||
scannedClasses.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClassScanned(String className) {
|
||||
synchronized (scannedClasses) {
|
||||
return scannedClasses.contains(className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether test package is sub package of parent package
|
||||
* @param testPkg
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
private boolean isSubPackage(String testPkg, String parent) {
|
||||
// child pkg startsWith parent pkg
|
||||
return testPkg.startsWith(parent);
|
||||
}
|
||||
|
||||
private String normalizePackage(String apackage) {
|
||||
if (!apackage.endsWith(".")) {
|
||||
apackage += ".";
|
||||
}
|
||||
return apackage;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegist
|
|||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
DubboBeanUtils.registerBeansIfNotExists(registry);
|
||||
|
||||
// register ConfigManager
|
||||
// register ConfigManager singleton
|
||||
beanFactory.registerSingleton(ConfigManager.BEAN_NAME, ApplicationModel.getConfigManager());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistra
|
|||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
|
||||
// @since 2.7.6 Register the common beans
|
||||
registerCommonBeans(registry);
|
||||
|
||||
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
|
||||
|
||||
registerServiceAnnotationPostProcessor(packagesToScan, registry);
|
||||
|
||||
// @since 2.7.6 Register the common beans
|
||||
registerCommonBeans(registry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ import org.apache.dubbo.config.ProtocolConfig;
|
|||
import org.apache.dubbo.config.ProviderConfig;
|
||||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.spring.Constants;
|
||||
import org.apache.dubbo.config.spring.ReferenceBean;
|
||||
import org.apache.dubbo.config.spring.ServiceBean;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
|
@ -278,7 +278,7 @@ public class DubboBeanDefinitionParser implements BeanDefinitionParser {
|
|||
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, beanName+"_decorated"));
|
||||
|
||||
// signal object type since Spring 5.2
|
||||
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
|
||||
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
|
||||
|
||||
//mark property value as optional
|
||||
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();
|
||||
|
|
|
|||
|
|
@ -19,10 +19,11 @@ package org.apache.dubbo.config.spring.util;
|
|||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
|
||||
import static org.springframework.util.ClassUtils.getAllInterfacesForClass;
|
||||
import static org.springframework.util.ClassUtils.resolveClassName;
|
||||
|
|
@ -59,14 +60,14 @@ public class DubboAnnotationUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolve the interface name from {@link AnnotationAttributes}
|
||||
* Resolve the interface name from annotation attributes
|
||||
*
|
||||
* @param attributes {@link AnnotationAttributes} instance, may be {@link Service @Service} or {@link Reference @Reference}
|
||||
* @param defaultInterfaceClass the default {@link Class class} of interface
|
||||
* @param attributes annotation attributes instance, may be {@link Service @Service} or {@link Reference @Reference}
|
||||
* @param defaultInterfaceClass the default class of interface
|
||||
* @return the interface name if found
|
||||
* @throws IllegalStateException if interface name was not found
|
||||
*/
|
||||
public static String resolveInterfaceName(AnnotationAttributes attributes, Class<?> defaultInterfaceClass) {
|
||||
public static String resolveInterfaceName(Map<String, Object> attributes, Class<?> defaultInterfaceClass) {
|
||||
Boolean generic = getAttribute(attributes, "generic");
|
||||
if (generic != null && generic) {
|
||||
// it's a generic reference
|
||||
|
|
@ -79,22 +80,22 @@ public class DubboAnnotationUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolve the {@link Class class} of Dubbo Service interface from the specified
|
||||
* {@link AnnotationAttributes annotation attributes} and annotated {@link Class class}.
|
||||
* Resolve the interface class of Dubbo Service annotation from the specified
|
||||
* annotation attributes and annotated class.
|
||||
*
|
||||
* @param attributes {@link AnnotationAttributes annotation attributes}
|
||||
* @param defaultInterfaceClass the annotated {@link Class class}.
|
||||
* @return the {@link Class class} of Dubbo Service interface
|
||||
* @param attributes annotation attributes
|
||||
* @param defaultInterfaceClass the annotated class.
|
||||
* @return the class of Dubbo Service interface
|
||||
* @throws IllegalArgumentException if can't resolved
|
||||
*/
|
||||
public static Class<?> resolveServiceInterfaceClass(AnnotationAttributes attributes, Class<?> defaultInterfaceClass)
|
||||
public static Class<?> resolveServiceInterfaceClass(Map<String, Object> attributes, Class<?> defaultInterfaceClass)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
ClassLoader classLoader = defaultInterfaceClass != null ? defaultInterfaceClass.getClassLoader() : Thread.currentThread().getContextClassLoader();
|
||||
|
||||
Class<?> interfaceClass = getAttribute(attributes, "interfaceClass");
|
||||
|
||||
if (void.class.equals(interfaceClass)) { // default or set void.class for purpose.
|
||||
if (interfaceClass == null || void.class.equals(interfaceClass)) { // default or set void.class for purpose.
|
||||
|
||||
interfaceClass = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.util;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;
|
||||
import org.apache.dubbo.config.spring.context.DubboConfigInitializationPostProcessor;
|
||||
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
|
||||
import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
|
||||
|
|
@ -58,12 +59,15 @@ public interface DubboBeanUtils {
|
|||
*/
|
||||
static void registerCommonBeans(BeanDefinitionRegistry registry) {
|
||||
|
||||
registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
|
||||
|
||||
registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
|
||||
|
||||
// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
|
||||
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
|
||||
ReferenceAnnotationBeanPostProcessor.class);
|
||||
|
||||
// TODO Whether DubboConfigAliasPostProcessor can be removed ?
|
||||
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
|
||||
registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
|
||||
DubboConfigAliasPostProcessor.class);
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ import org.apache.dubbo.config.ProtocolConfig;
|
|||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
import org.apache.dubbo.config.context.ConfigManager;
|
||||
import org.apache.dubbo.config.spring.api.DemoService;
|
||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
||||
import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
|
||||
import org.apache.dubbo.rpc.Constants;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
|
@ -38,7 +40,6 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class JavaConfigBeanTest {
|
||||
|
|
@ -70,15 +71,12 @@ public class JavaConfigBeanTest {
|
|||
SysProps.setProperty("dubbo.protocol.port", "2346");
|
||||
String registryAddress = "zookeeper://127.0.0.1:2181";
|
||||
SysProps.setProperty("dubbo.registry.address", registryAddress);
|
||||
SysProps.setProperty("dubbo.provider.group", "test");
|
||||
|
||||
// test destroy flag
|
||||
// MockServiceDiscovery mockServiceDiscovery = (MockServiceDiscovery) ExtensionLoader.getExtensionLoader(ServiceDiscovery.class).getExtension("mock");
|
||||
// Assertions.assertEquals(false, mockServiceDiscovery.isDestroySucceed());
|
||||
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
|
||||
TestConfiguration.class, ReferenceConfiguration.class);
|
||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(
|
||||
TestConfiguration.class, ConsumerConfiguration.class, ProviderConfiguration.class);
|
||||
try {
|
||||
applicationContext.start();
|
||||
consumerContext.start();
|
||||
|
||||
ConfigManager configManager = ApplicationModel.getConfigManager();
|
||||
ApplicationConfig application = configManager.getApplication().get();
|
||||
|
|
@ -101,7 +99,7 @@ public class JavaConfigBeanTest {
|
|||
Assertions.assertEquals(false, consumerConfig.isCheck());
|
||||
Assertions.assertEquals(2, consumerConfig.getRetries());
|
||||
|
||||
Map<String, ReferenceBean> referenceBeanMap = applicationContext.getBeansOfType(ReferenceBean.class);
|
||||
Map<String, ReferenceBean> referenceBeanMap = consumerContext.getBeansOfType(ReferenceBean.class);
|
||||
Assertions.assertEquals(1, referenceBeanMap.size());
|
||||
ReferenceBean referenceBean = referenceBeanMap.get("&demoService");
|
||||
Assertions.assertNotNull(referenceBean);
|
||||
|
|
@ -112,12 +110,14 @@ public class JavaConfigBeanTest {
|
|||
// consumer cannot override reference's attribute
|
||||
Assertions.assertEquals(5, referenceConfig.getRetries());
|
||||
|
||||
} finally {
|
||||
applicationContext.close();
|
||||
}
|
||||
DemoService referProxy = (DemoService) referenceConfig.get();
|
||||
Assertions.assertTrue( referProxy instanceof DemoService);
|
||||
String result = referProxy.sayName("dubbo");
|
||||
Assertions.assertEquals("say:dubbo", result);
|
||||
|
||||
// test destroy flag
|
||||
//Assertions.assertEquals(true, mockServiceDiscovery.isDestroySucceed());
|
||||
} finally {
|
||||
consumerContext.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ public class JavaConfigBeanTest {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
static class ReferenceConfiguration {
|
||||
static class ConsumerConfiguration {
|
||||
|
||||
@Bean
|
||||
@DubboReference(scope = Constants.SCOPE_LOCAL, retries = 5)
|
||||
|
|
@ -169,4 +169,14 @@ public class JavaConfigBeanTest {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
@DubboService(group = "demo")
|
||||
public DemoService demoServiceImpl() {
|
||||
return new DemoServiceImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.config.spring.beans.factory.annotation;
|
|||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
import org.apache.dubbo.config.spring.ServiceBean;
|
||||
import org.apache.dubbo.config.spring.api.HelloService;
|
||||
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -45,7 +46,8 @@ import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER
|
|||
@ContextConfiguration(
|
||||
classes = {
|
||||
ServiceAnnotationTestConfiguration.class,
|
||||
ServiceAnnotationPostProcessorTest.class
|
||||
ServiceAnnotationPostProcessorTest.class,
|
||||
ServiceAnnotationPostProcessorTest.DuplicatedScanConfig.class
|
||||
})
|
||||
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
|
||||
@TestPropertySource(properties = {
|
||||
|
|
@ -81,7 +83,7 @@ public class ServiceAnnotationPostProcessorTest {
|
|||
Map<String, ServiceAnnotationPostProcessor> beanPostProcessorsMap =
|
||||
beanFactory.getBeansOfType(ServiceAnnotationPostProcessor.class);
|
||||
|
||||
Assertions.assertEquals(1, beanPostProcessorsMap.size());
|
||||
Assertions.assertEquals(2, beanPostProcessorsMap.size());
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -98,4 +100,9 @@ public class ServiceAnnotationPostProcessorTest {
|
|||
|
||||
}
|
||||
|
||||
@DubboComponentScan({"org.apache.dubbo.config.spring.context.annotation", "${provider.package}"})
|
||||
static class DuplicatedScanConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.extension;
|
|||
|
||||
import org.apache.dubbo.common.extension.ExtensionFactory;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
import org.apache.dubbo.config.spring.api.DemoService;
|
||||
import org.apache.dubbo.config.spring.api.HelloService;
|
||||
import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
|
||||
|
|
@ -41,6 +42,8 @@ public class SpringExtensionFactoryTest {
|
|||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
DubboBootstrap.reset();
|
||||
|
||||
// init SpringExtensionFactory
|
||||
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getExtension("spring");
|
||||
|
||||
|
|
@ -56,6 +59,13 @@ public class SpringExtensionFactoryTest {
|
|||
SpringExtensionFactory.addApplicationContext(context2);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void destroy() {
|
||||
context1.close();
|
||||
context2.close();
|
||||
SpringExtensionFactory.clearContexts();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExtensionBySPI() {
|
||||
Protocol protocol = springExtensionFactory.getExtension(Protocol.class, "protocol");
|
||||
|
|
@ -70,13 +80,6 @@ public class SpringExtensionFactoryTest {
|
|||
Assertions.assertNotNull(hello);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void destroy() {
|
||||
SpringExtensionFactory.clearContexts();
|
||||
context1.close();
|
||||
context2.close();
|
||||
}
|
||||
|
||||
@Bean("bean1")
|
||||
public DemoService bean1() {
|
||||
return new DemoServiceImpl();
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
|
||||
<properties>
|
||||
<!-- Common libs -->
|
||||
<!-- <spring_version>4.3.30.RELEASE</spring_version> -->
|
||||
<spring_version>5.2.8.RELEASE</spring_version>
|
||||
<javassist_version>3.23.1-GA</javassist_version>
|
||||
<eclipse_collections_version>10.4.0</eclipse_collections_version>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public abstract class AbstractRequestAnnotationParameterProcessor extends Abstra
|
|||
|
||||
private boolean isDefaultValue(Annotation annotation, String attributeName, Object attributeValue) {
|
||||
String defaultValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
|
||||
return Objects.equals(attributeValue, defaultValue);
|
||||
return Objects.deepEquals(attributeValue, defaultValue);
|
||||
}
|
||||
|
||||
protected boolean isEmpty(String str) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
|
@ -71,7 +70,6 @@ public class DubboAutoConfiguration implements ApplicationContextAware, BeanDefi
|
|||
*/
|
||||
@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
|
||||
@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
|
||||
Set<String> packagesToScan) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue