Native Support Springboot3 (#12072)

* Support native with springboot3

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* fix checkstyle

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* remove useless imports

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* remove useless imports

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* change java version of  build-source actions to jdk17

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* dubbo-serialization-fastjson2 support native

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* fix xml config

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* fix singleton bean

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* ignore test

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* ignore dubbo-config-spring6 module in dubbo all

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* remove @ignore

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* add dubbo-config-spring6 to dubbo-bom

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* add dubbo-config-spring6 to dubbo-test

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* add transformer

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* ignore  dubbo-config-spring6

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* fix JsonUtilsTest

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

* fix JsonUtilsTest

Signed-off-by: crazyhzm <crazyhzm@gmail.com>

---------

Signed-off-by: crazyhzm <crazyhzm@gmail.com>
This commit is contained in:
huazhongming 2023-04-25 11:30:17 +08:00 committed by GitHub
parent 2997fa6a2e
commit 6c8f79c889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
99 changed files with 2806 additions and 157 deletions

View File

@ -54,7 +54,7 @@ jobs:
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
java-version: 17
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:

View File

@ -96,8 +96,8 @@ header:
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ExecutableMode.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/MemberCategory.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java'
- 'dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/**'
comment: on-failure

View File

@ -0,0 +1,34 @@
/*
* 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.common.aot;
public abstract class NativeDetector {
/**
* See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
*/
private static final boolean IMAGE_CODE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
/**
* Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.
*/
public static boolean inNativeImage() {
return IMAGE_CODE;
}
}

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.common.extension;
import org.apache.dubbo.common.Extension;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.common.beans.support.InstantiationStrategy;
import org.apache.dubbo.common.context.Lifecycle;
import org.apache.dubbo.common.extension.support.ActivateComparator;
@ -33,7 +34,6 @@ import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.NativeUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -107,8 +107,8 @@ public class ExtensionLoader<T> {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(
ExtensionLoader.class);
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
private static final String SPECIAL_SPI_PROPERTIES = "special_spi.properties";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
private static final String SPECIAL_SPI_PROPERTIES = "special_spi.properties";
private final ConcurrentMap<Class<?>, Object> extensionInstances = new ConcurrentHashMap<>(64);
@ -120,17 +120,17 @@ public class ExtensionLoader<T> {
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
private final Map<String, Object> cachedActivates = Collections.synchronizedMap(
private final Map<String, Object> cachedActivates = Collections.synchronizedMap(
new LinkedHashMap<>());
private final Map<String, Set<String>> cachedActivateGroups = Collections.synchronizedMap(
private final Map<String, Set<String>> cachedActivateGroups = Collections.synchronizedMap(
new LinkedHashMap<>());
private final Map<String, String[][]> cachedActivateValues = Collections.synchronizedMap(
private final Map<String, String[][]> cachedActivateValues = Collections.synchronizedMap(
new LinkedHashMap<>());
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
private volatile Class<?> cachedAdaptiveClass = null;
private String cachedDefaultName;
private volatile Throwable createAdaptiveInstanceError;
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
private volatile Class<?> cachedAdaptiveClass = null;
private String cachedDefaultName;
private volatile Throwable createAdaptiveInstanceError;
private Set<Class<?>> cachedWrapperClasses;
@ -148,13 +148,13 @@ public class ExtensionLoader<T> {
/**
* Record all unacceptable exceptions when using SPI
*/
private final Set<String> unacceptableExceptions = new ConcurrentHashSet<>();
private final ExtensionDirector extensionDirector;
private final Set<String> unacceptableExceptions = new ConcurrentHashSet<>();
private final ExtensionDirector extensionDirector;
private final List<ExtensionPostProcessor> extensionPostProcessors;
private InstantiationStrategy instantiationStrategy;
private final ActivateComparator activateComparator;
private final ScopeModel scopeModel;
private final AtomicBoolean destroyed = new AtomicBoolean();
private InstantiationStrategy instantiationStrategy;
private final ActivateComparator activateComparator;
private final ScopeModel scopeModel;
private final AtomicBoolean destroyed = new AtomicBoolean();
public static void setLoadingStrategies(LoadingStrategy... strategies) {
if (ArrayUtils.isNotEmpty(strategies)) {
@ -1409,7 +1409,7 @@ public class ExtensionLoader<T> {
// Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader
ClassLoader classLoader = type.getClassLoader();
try {
if (NativeUtils.isNative()) {
if (NativeDetector.inNativeImage()) {
return classLoader.loadClass(type.getName() + "$Adaptive");
}
} catch (Throwable ignore) {

View File

@ -16,11 +16,14 @@
*/
package org.apache.dubbo.common.json;
import org.apache.dubbo.common.extension.SPI;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public interface JSON {
@SPI
public interface JsonUtil {
boolean isSupport();
<T> T toJavaObject(String json, Type type);

View File

@ -16,7 +16,7 @@
*/
package org.apache.dubbo.common.json.impl;
import org.apache.dubbo.common.json.JSON;
import org.apache.dubbo.common.json.JsonUtil;
import org.apache.dubbo.common.utils.CollectionUtils;
import java.util.HashMap;
@ -24,7 +24,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public abstract class AbstractJSONImpl implements JSON {
public abstract class AbstractJsonUtilImpl implements JsonUtil {
@Override
public boolean isSupport() {
try {

View File

@ -21,7 +21,7 @@ import com.alibaba.fastjson2.JSONWriter;
import java.lang.reflect.Type;
import java.util.List;
public class FastJson2Impl extends AbstractJSONImpl {
public class FastJson2Impl extends AbstractJsonUtilImpl {
@Override
public <T> T toJavaObject(String json, Type type) {
return com.alibaba.fastjson2.JSON.parseObject(json, type);

View File

@ -21,7 +21,7 @@ import com.alibaba.fastjson.serializer.SerializerFeature;
import java.lang.reflect.Type;
import java.util.List;
public class FastJsonImpl extends AbstractJSONImpl {
public class FastJsonImpl extends AbstractJsonUtilImpl {
@Override
public <T> T toJavaObject(String json, Type type) {

View File

@ -22,7 +22,7 @@ import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class GsonImpl extends AbstractJSONImpl {
public class GsonImpl extends AbstractJsonUtilImpl {
// weak reference of com.google.gson.Gson, prevent throw exception when init
private volatile Object gsonCache = null;

View File

@ -26,7 +26,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.lang.reflect.Type;
import java.util.List;
public class JacksonImpl extends AbstractJSONImpl {
public class JacksonImpl extends AbstractJsonUtilImpl {
private final ObjectMapper objectMapper = new ObjectMapper();
private volatile Object jacksonCache = null;

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.resource.GlobalResourcesRepository;
@ -78,7 +79,7 @@ public class ClassLoaderResourceLoader {
Enumeration<URL> urls;
try {
urls = currentClassLoader.getResources(fileName);
boolean isNative = NativeUtils.isNative();
boolean isNative = NativeDetector.inNativeImage();
if (urls != null) {
while (urls.hasMoreElements()) {
URL url = urls.nextElement();

View File

@ -17,7 +17,7 @@
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.json.JSON;
import org.apache.dubbo.common.json.JsonUtil;
import org.apache.dubbo.common.json.impl.FastJson2Impl;
import org.apache.dubbo.common.json.impl.FastJsonImpl;
import org.apache.dubbo.common.json.impl.GsonImpl;
@ -29,17 +29,16 @@ import java.util.List;
import java.util.Map;
public class JsonUtils {
private static volatile JsonUtil jsonUtil;
private static volatile JSON json;
protected static JSON getJson() {
if (json == null) {
protected static JsonUtil getJson() {
if (jsonUtil == null) {
synchronized (JsonUtils.class) {
if (json == null) {
if (jsonUtil == null) {
String preferJsonFrameworkName = System.getProperty(CommonConstants.PREFER_JSON_FRAMEWORK_NAME);
if (StringUtils.isNotEmpty(preferJsonFrameworkName)) {
try {
JSON instance = null;
JsonUtil instance = null;
switch (preferJsonFrameworkName) {
case "fastjson2":
instance = new FastJson2Impl();
@ -55,23 +54,23 @@ public class JsonUtils {
break;
}
if (instance != null && instance.isSupport()) {
json = instance;
jsonUtil = instance;
}
} catch (Throwable ignore) {
}
}
if (json == null) {
List<Class<? extends JSON>> jsonClasses = Arrays.asList(
if (jsonUtil == null) {
List<Class<? extends JsonUtil>> jsonClasses = Arrays.asList(
FastJson2Impl.class,
FastJsonImpl.class,
GsonImpl.class,
JacksonImpl.class);
for (Class<? extends JSON> jsonClass : jsonClasses) {
for (Class<? extends JsonUtil> jsonClass : jsonClasses) {
try {
JSON instance = jsonClass.getConstructor().newInstance();
JsonUtil instance = jsonClass.getConstructor().newInstance();
if (instance.isSupport()) {
json = instance;
jsonUtil = instance;
break;
}
} catch (Throwable ignore) {
@ -79,22 +78,22 @@ public class JsonUtils {
}
}
}
if (json == null) {
if (jsonUtil == null) {
throw new IllegalStateException("Dubbo unable to find out any json framework (e.g. fastjson2, fastjson, gson, jackson) from jvm env. " +
"Please import at least one json framework.");
}
}
}
}
return json;
return jsonUtil;
}
/**
* @deprecated for uts only
*/
@Deprecated
protected static void setJson(JSON json) {
JsonUtils.json = json;
protected static void setJson(JsonUtil json) {
JsonUtils.jsonUtil = json;
}
public static <T> T toJavaObject(String json, Type type) {

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.config;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.config.Environment;
import org.apache.dubbo.common.config.InmemoryConfiguration;
@ -47,7 +48,6 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.NATIVE;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
@ -292,8 +292,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
* @return
*/
protected String[] methods(Class<?> interfaceClass) {
boolean isNative = getEnvironment().getConfiguration().getBoolean(NATIVE, false);
if (isNative) {
if (NativeDetector.inNativeImage()) {
return Arrays.stream(interfaceClass.getMethods()).map(Method::getName).toArray(String[]::new);
} else {
return ClassUtils.getMethodNames(interfaceClass);

View File

@ -0,0 +1,4 @@
fastjson2=org.apache.dubbo.common.json.impl.FastJson2Impl
fastjson=org.apache.dubbo.common.json.impl.FastJsonImpl
gson=org.apache.dubbo.common.json.impl.GsonImpl
jackson=org.apache.dubbo.common.json.impl.JacksonImpl

View File

@ -16,7 +16,7 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.json.JSON;
import org.apache.dubbo.common.json.JsonUtil;
import org.apache.dubbo.common.json.impl.FastJson2Impl;
import org.apache.dubbo.common.json.impl.FastJsonImpl;
import org.apache.dubbo.common.json.impl.GsonImpl;
@ -319,10 +319,10 @@ class JsonUtilsTest {
private static Field jsonFieldCache;
private static void setJson(JSON json) {
private static void setJson(JsonUtil json) {
try {
if (jsonFieldCache == null) {
jsonFieldCache = JsonUtils.class.getDeclaredField("json");
jsonFieldCache = JsonUtils.class.getDeclaredField("jsonUtil");
jsonFieldCache.setAccessible(true);
}

View File

@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
@ -74,14 +75,14 @@ import java.util.Map;
* }
* }
* </pre>
*
* <p>
* Or register ReferenceBean in xml:
* <pre class="code">
* &lt;dubbo:reference id="helloService" interface="org.apache.dubbo.config.spring.api.HelloService"/&gt;
* &lt;!-- As GenericService --&gt;
* &lt;dubbo:reference id="genericHelloService" interface="org.apache.dubbo.config.spring.api.HelloService" generic="true"/&gt;
* </pre>
*
* <p>
* Step 2: Inject ReferenceBean by @Autowired
* <pre class="code">
* public class FooController {
@ -93,12 +94,11 @@ import java.util.Map;
* }
* </pre>
*
*
* @see org.apache.dubbo.config.annotation.DubboReference
* @see org.apache.dubbo.config.spring.reference.ReferenceBeanBuilder
*/
public class ReferenceBean<T> implements FactoryBean<T>,
ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {
ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {
private transient ApplicationContext applicationContext;
@ -134,7 +134,7 @@ public class ReferenceBean<T> implements FactoryBean<T>,
private ReferenceConfig referenceConfig;
// Registration sources of this reference, may be xml file or annotation location
private List<Map<String,Object>> sources = new ArrayList<>();
private List<Map<String, Object>> sources = new ArrayList<>();
public ReferenceBean() {
super();
@ -164,24 +164,23 @@ public class ReferenceBean<T> implements FactoryBean<T>,
*
* <p></p>
* Why we need a lazy proxy?
*
* <p>
* <p/>
* When Spring searches beans by type, if Spring cannot determine the type of a factory bean, it may try to initialize it.
* The ReferenceBean is also a FactoryBean.
* <br/>
* (This has already been resolved by decorating the BeanDefinition: {@link DubboBeanDefinitionParser#configReferenceBean})
*
* <p>
* <p/>
* In addition, if some ReferenceBeans are dependent on beans that are initialized very early,
* and dubbo config beans are not ready yet, there will be many unexpected problems if initializing the dubbo reference immediately.
*
* <p>
* <p/>
* When it is initialized, only a lazy proxy object will be created,
* and dubbo reference-related resources will not be initialized.
* <br/>
* In this way, the influence of Spring is eliminated, and the dubbo configuration initialization is controllable.
*
*
* @see DubboConfigBeanInitializer
* @see ReferenceBeanManager#initReferenceBean(ReferenceBean)
* @see DubboBeanDefinitionParser#configReferenceBean
@ -212,8 +211,14 @@ public class ReferenceBean<T> implements FactoryBean<T>,
// pre init xml reference bean or @DubboReference annotation
Assert.notEmptyString(getId(), "The id of ReferenceBean cannot be empty");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());
this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
if (AotWithSpringDetector.useGeneratedArtifacts()) {
this.interfaceClass = (Class<?>) beanDefinition.getPropertyValues().get(ReferenceAttributes.INTERFACE_CLASS);
this.interfaceName = (String) beanDefinition.getPropertyValues().get(ReferenceAttributes.INTERFACE_NAME);
} else {
this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
}
Assert.notNull(this.interfaceClass, "The interface class of ReferenceBean is not initialized");
if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {
@ -261,6 +266,7 @@ public class ReferenceBean<T> implements FactoryBean<T>,
/**
* The interface of this ReferenceBean, for injection purpose
*
* @return
*/
public Class<?> getInterfaceClass() {
@ -347,7 +353,7 @@ public class ReferenceBean<T> implements FactoryBean<T>,
//Subclasses should synchronize on the given Object if they perform any sort of extended singleton creation phase.
// In particular, subclasses should not have their own mutexes involved in singleton creation, to avoid the potential for deadlocks in lazy-init situations.
//The redundant type cast is to be compatible with earlier than spring-4.2
synchronized (((DefaultSingletonBeanRegistry)getBeanFactory()).getSingletonMutex()) {
synchronized (((DefaultSingletonBeanRegistry) getBeanFactory()).getSingletonMutex()) {
return referenceConfig.get();
}
}
@ -365,4 +371,11 @@ public class ReferenceBean<T> implements FactoryBean<T>,
}
}
public void setInterfaceClass(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.aot;
import org.apache.dubbo.common.aot.NativeDetector;
import org.springframework.core.SpringProperties;
public abstract class AotWithSpringDetector {
/**
* System property that indicates the application should run with AOT
* generated artifacts. If such optimizations are not available, it is
* recommended to throw an exception rather than fall back to the regular
* runtime behavior.
*/
public static final String AOT_ENABLED = "spring.aot.enabled";
/**
* Determine whether AOT optimizations must be considered at runtime. This
* is mandatory in a native image but can be triggered on the JVM using
* the {@value #AOT_ENABLED} Spring property.
*
* @return whether AOT optimizations must be considered
*/
public static boolean useGeneratedArtifacts() {
return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_ENABLED));
}
}

View File

@ -368,6 +368,11 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
if (targetClass.isAssignableFrom(clazz) && clazz.getName().contains("$$EnhancerBySpringCGLIB$$")) {
return false;
}
if (targetClass.isAssignableFrom(clazz) && clazz.getName().contains("$$SpringCGLIB$$")) {
return false;
}
return true;
}
}
@ -377,11 +382,11 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
*/
protected class AnnotatedInjectElement extends InjectionMetadata.InjectedElement {
protected final AnnotationAttributes attributes;
public final AnnotationAttributes attributes;
protected volatile Object injectedObject;
public volatile Object injectedObject;
private Class<?> injectedType;
public Class<?> injectedType;
protected AnnotatedInjectElement(Member member, PropertyDescriptor pd, AnnotationAttributes attributes) {
super(member, pd);
@ -438,7 +443,7 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
protected class AnnotatedMethodElement extends AnnotatedInjectElement {
protected final Method method;
public final Method method;
protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes) {
super(method, pd, attributes);
@ -448,7 +453,7 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
public class AnnotatedFieldElement extends AnnotatedInjectElement {
protected final Field field;
public final Field field;
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {
super(field, null, attributes);

View File

@ -94,7 +94,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
/**
* The bean name of {@link ReferenceAnnotationBeanPostProcessor}
*/
public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";
public static final String BEAN_NAME = ReferenceAnnotationBeanPostProcessor.class.getName();
/**
* Cache size
@ -314,6 +314,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
* Alternatives to the {@link #postProcessProperties(PropertyValues, Object, String)}, that removed as of Spring
* Framework 6.0.0, and in favor of {@link #postProcessProperties(PropertyValues, Object, String)}.
* <p>In order to be compatible with the lower version of Spring, it is still retained.
*
* @see #postProcessProperties
*/
public PropertyValues postProcessPropertyValues(
@ -323,6 +324,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
/**
* Alternatives to the {@link #postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)}.
*
* @see #postProcessPropertyValues
*/
@Override
@ -417,7 +419,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
boolean isContains;
if ((isContains = beanDefinitionRegistry.containsBeanDefinition(referenceBeanName)) || beanDefinitionRegistry.isAlias(referenceBeanName)) {
String preReferenceBeanName = referenceBeanName;
if (!isContains){
if (!isContains) {
// Look in the alias for the origin bean name
String[] aliases = beanDefinitionRegistry.getAliases(referenceBeanName);
if (ArrayUtils.isNotEmpty(aliases)) {

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;
import com.alibaba.spring.util.AnnotationUtils;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ClassUtils;
@ -27,12 +28,11 @@ 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.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import com.alibaba.spring.util.AnnotationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
@ -78,12 +78,13 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.alibaba.spring.util.ObjectUtils.of;
import static java.util.Arrays.asList;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUPLICATED_BEAN_DEFINITION;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_ANNOTATIONS_FOUND;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_BEANS_SCANNED;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUPLICATED_BEAN_DEFINITION;
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.resolveInterfaceName;
@ -128,7 +129,7 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
private BeanDefinitionRegistry registry;
private ServicePackagesHolder servicePackagesHolder;
protected ServicePackagesHolder servicePackagesHolder;
private volatile boolean scanned = false;
@ -136,12 +137,8 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
this(asList(packagesToScan));
}
public ServiceAnnotationPostProcessor(Collection<String> packagesToScan) {
this(new LinkedHashSet<>(packagesToScan));
}
public ServiceAnnotationPostProcessor(Set<String> packagesToScan) {
this.packagesToScan = packagesToScan;
public ServiceAnnotationPostProcessor(Collection<?> packagesToScan) {
this.packagesToScan = (Set<String>) packagesToScan.stream().collect(Collectors.toSet());
}
@Override
@ -217,6 +214,9 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
continue;
}
if(AotWithSpringDetector.useGeneratedArtifacts()){
scanner.setIncludeAnnotationConfig(false);
}
// Registers @Service Bean first
scanner.scan(packageToScan);

View File

@ -34,6 +34,7 @@ import org.apache.dubbo.config.context.AbstractConfigManager;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.spring.ConfigCenterBean;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.beans.BeansException;
@ -66,7 +67,6 @@ public class DubboConfigBeanInitializer implements BeanFactoryAware, Initializin
private ConfigurableListableBeanFactory beanFactory;
private ReferenceBeanManager referenceBeanManager;
@Autowired
private ConfigManager configManager;
@Autowired
@ -86,6 +86,7 @@ public class DubboConfigBeanInitializer implements BeanFactoryAware, Initializin
private void init() {
if (initialized.compareAndSet(false, true)) {
referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
configManager = DubboBeanUtils.getConfigManager(beanFactory);
try {
prepareDubboConfigBeans();
referenceBeanManager.prepareReferenceBeans();

View File

@ -0,0 +1,79 @@
/*
* 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.context.ConfigManager;
import org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar;
import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.config.spring.util.EnvironmentUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.SortedMap;
public class DubboContextPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
/**
* The bean name of {@link DubboConfigConfigurationRegistrar}
*/
public final static String BEAN_NAME = "dubboContextPostProcessor";
private BeanDefinitionRegistry registry;
private ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(beanFactory);
ModuleModel moduleModel = DubboBeanUtils.getModuleModel(beanFactory);
// Initialize SpringExtensionInjector
SpringExtensionInjector.get(applicationModel).init(applicationContext);
SpringExtensionInjector.get(moduleModel).init(applicationContext);
DubboBeanUtils.getInitializationContext(beanFactory).setApplicationContext(applicationContext);
// Initialize dubbo Environment before ConfigManager
// Extract dubbo props from Spring env and put them to app config
ConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();
SortedMap<String, String> dubboProperties = EnvironmentUtils.filterDubboProperties(environment);
applicationModel.getModelEnvironment().setAppConfigMap(dubboProperties);
// register ConfigManager singleton
beanFactory.registerSingleton(ConfigManager.BEAN_NAME, applicationModel.getApplicationConfigManager());
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
DubboSpringInitializer.initialize(beanDefinitionRegistry);
this.registry = beanDefinitionRegistry;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -16,23 +16,14 @@
*/
package org.apache.dubbo.config.spring.context;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.config.spring.util.EnvironmentUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.SortedMap;
/**
@ -73,23 +64,6 @@ public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegist
DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);
}
ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(beanFactory);
ModuleModel moduleModel = DubboBeanUtils.getModuleModel(beanFactory);
// Initialize SpringExtensionInjector
SpringExtensionInjector.get(applicationModel).init(applicationContext);
SpringExtensionInjector.get(moduleModel).init(applicationContext);
DubboBeanUtils.getInitializationContext(beanFactory).setApplicationContext(applicationContext);
// Initialize dubbo Environment before ConfigManager
// Extract dubbo props from Spring env and put them to app config
ConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();
SortedMap<String, String> dubboProperties = EnvironmentUtils.filterDubboProperties(environment);
applicationModel.getModelEnvironment().setAppConfigMap(dubboProperties);
// register ConfigManager singleton
beanFactory.registerSingleton(ConfigManager.BEAN_NAME, applicationModel.getApplicationConfigManager());
// fix https://github.com/apache/dubbo/issues/10278
if (registry != null){
registry.removeBeanDefinition(BEAN_NAME);

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.context;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
@ -43,7 +44,7 @@ public class DubboSpringInitializer {
private static final Map<BeanDefinitionRegistry, DubboSpringInitContext> contextMap = new ConcurrentHashMap<>();
private DubboSpringInitializer() {
public DubboSpringInitializer() {
}
public static void initialize(BeanDefinitionRegistry registry) {
@ -140,8 +141,10 @@ public class DubboSpringInitializer {
context.markAsBound();
moduleModel.setLifeCycleManagedExternally(true);
// register common beans
DubboBeanUtils.registerCommonBeans(registry);
if (!AotWithSpringDetector.useGeneratedArtifacts()){
// register common beans
DubboBeanUtils.registerCommonBeans(registry);
}
}
private static String safeGetModelDesc(ScopeModel scopeModel) {
@ -163,9 +166,15 @@ public class DubboSpringInitializer {
private static void registerContextBeans(ConfigurableListableBeanFactory beanFactory, DubboSpringInitContext context) {
// register singleton
registerSingleton(beanFactory, context);
registerSingleton(beanFactory, context.getApplicationModel());
registerSingleton(beanFactory, context.getModuleModel());
if (!beanFactory.containsSingleton(DubboSpringInitContext.class.getName())){
registerSingleton(beanFactory, context);
}
if (!beanFactory.containsSingleton(context.getApplicationModel().getClass().getName())){
registerSingleton(beanFactory, context.getApplicationModel());
}
if (!beanFactory.containsSingleton(context.getModuleModel().getClass().getName())){
registerSingleton(beanFactory, context.getModuleModel());
}
}
private static void registerSingleton(ConfigurableListableBeanFactory beanFactory, Object bean) {

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.config.spring.context.annotation;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
@ -53,7 +54,9 @@ public class DubboClassPathBeanDefinitionScanner extends ClassPathBeanDefinition
setResourceLoader(resourceLoader);
registerAnnotationConfigProcessors(registry);
if (!AotWithSpringDetector.useGeneratedArtifacts()) {
registerAnnotationConfigProcessors(registry);
}
}

View File

@ -20,7 +20,7 @@ import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.context.DubboSpringInitializer;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@ -70,7 +70,7 @@ public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistra
*/
private void registerServiceAnnotationPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationPostProcessor.class);
BeanDefinitionBuilder builder = rootBeanDefinition(SpringCompatUtils.serviceAnnotationPostProcessor());
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.annotation.ProvidedBy;
import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.beans.MutablePropertyValues;
@ -124,7 +125,12 @@ public class ReferenceBeanSupport {
public static String generateReferenceKey(Map<String, Object> attributes, ApplicationContext applicationContext) {
String interfaceClass = (String) attributes.get(ReferenceAttributes.INTERFACE);
String interfaceClass;
if (AotWithSpringDetector.useGeneratedArtifacts()) {
interfaceClass = (String) attributes.get(ReferenceAttributes.INTERFACE_NAME);
} else {
interfaceClass = (String) attributes.get(ReferenceAttributes.INTERFACE);
}
Assert.notEmptyString(interfaceClass, "No interface class or name found from attributes");
String group = (String) attributes.get(ReferenceAttributes.GROUP);
String version = (String) attributes.get(ReferenceAttributes.VERSION);

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.config.spring.schema;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
@ -73,7 +74,7 @@ public class AnnotationBeanDefinitionParser extends AbstractSingleBeanDefinition
@Override
protected Class<?> getBeanClass(Element element) {
return ServiceAnnotationPostProcessor.class;
return SpringCompatUtils.serviceAnnotationPostProcessor();
}
}

View File

@ -30,6 +30,7 @@ import org.apache.dubbo.config.TracingConfig;
import org.apache.dubbo.config.spring.ConfigCenterBean;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.beans.factory.config.ConfigurableSourceBeanMetadataElement;
import org.apache.dubbo.config.spring.context.DubboSpringInitializer;
@ -94,6 +95,8 @@ public class DubboNamespaceHandler extends NamespaceHandlerSupport implements Co
* @since 2.7.5
*/
private void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
if (!AotWithSpringDetector.useGeneratedArtifacts()) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
}
}
}

View File

@ -16,21 +16,22 @@
*/
package org.apache.dubbo.config.spring.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;
import org.apache.dubbo.config.spring.context.DubboConfigApplicationListener;
import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
import org.apache.dubbo.config.spring.context.DubboContextPostProcessor;
import org.apache.dubbo.config.spring.context.DubboDeployApplicationListener;
import org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;
import org.apache.dubbo.config.spring.context.DubboSpringInitContext;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
@ -66,11 +67,13 @@ public interface DubboBeanUtils {
registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
registerInfrastructureBean(registry, DubboContextPostProcessor.BEAN_NAME, DubboContextPostProcessor.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);
registerInfrastructureBean(registry, SpringCompatUtils.referenceAnnotationBeanPostProcessor().getName(),
SpringCompatUtils.referenceAnnotationBeanPostProcessor());
// TODO Whether DubboConfigAliasPostProcessor can be removed ?
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
@ -89,7 +92,7 @@ public interface DubboBeanUtils {
registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
// register infra bean if not exists later
registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, SpringCompatUtils.dubboInfraBeanRegisterPostProcessor());
}
/**
@ -203,4 +206,12 @@ public interface DubboBeanUtils {
return null;
}
static ConfigManager getConfigManager(BeanFactory beanFactory) {
String beanName = ConfigManager.BEAN_NAME;
if (beanFactory.containsBean(beanName)) {
return beanFactory.getBean(beanName, ConfigManager.class);
}
return null;
}
}

View File

@ -18,6 +18,9 @@ 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.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
@ -30,7 +33,7 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Spring Compatibility Utils for spring 3.x/4.x/5.x
* Spring Compatibility Utils for spring 3.x/4.x/5.x/6.x
*/
public class SpringCompatUtils {
@ -127,4 +130,28 @@ public class SpringCompatUtils {
}
return null;
}
public static Class<?> referenceAnnotationBeanPostProcessor(){
try {
return Class.forName("org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor");
} catch (ClassNotFoundException e) {
return ReferenceAnnotationBeanPostProcessor.class;
}
}
public static Class<?> serviceAnnotationPostProcessor(){
try {
return Class.forName("org.apache.dubbo.config.spring6.beans.factory.annotation.ServiceAnnotationWithAotPostProcessor");
} catch (ClassNotFoundException e) {
return ServiceAnnotationPostProcessor.class;
}
}
public static Class<?> dubboInfraBeanRegisterPostProcessor(){
try {
return Class.forName("org.apache.dubbo.config.spring6.context.DubboInfraBeanRegisterPostProcessor");
} catch (ClassNotFoundException e) {
return DubboInfraBeanRegisterPostProcessor.class;
}
}
}

View File

@ -0,0 +1,94 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config</artifactId>
<version>${revision}</version>
</parent>
<artifactId>dubbo-config-spring6</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>6.0.7</spring.version>
<spring-boot.version>3.0.4</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-vintage-engine</artifactId>
<groupId>org.junit.vintage</groupId>
</exclusion>
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,841 @@
/*
* 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.spring6.beans.factory.annotation;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;
import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedFieldValueResolver;
import org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedMethodArgumentsResolver;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aot.generate.AccessControl;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.support.ClassHintUtils;
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.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.aot.AutowiredArgumentsCodeGenerator;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.MethodMetadata;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;
import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
import static org.springframework.util.StringUtils.hasText;
/**
* <p>
* Step 1:
* The purpose of implementing {@link BeanFactoryPostProcessor} is to scan the registration reference bean definition earlier,
* so that it can be shared with the xml bean configuration.
* </p>
*
* <p>
* Step 2:
* By implementing {@link org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor},
* inject the reference bean instance into the fields and setter methods which annotated with {@link DubboReference}.
* </p>
*
* @see DubboReference
* @see Reference
* @see com.alibaba.dubbo.config.annotation.Reference
* @since 2.5.7
*/
public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotationBeanPostProcessor
implements ApplicationContextAware, BeanRegistrationAotProcessor, BeanFactoryPostProcessor {
/**
* The bean name of {@link ReferenceAnnotationWithAotBeanPostProcessor}
*/
public static final String BEAN_NAME = ReferenceAnnotationWithAotBeanPostProcessor.class.getName();
/**
* Cache size
*/
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedFieldReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private ApplicationContext applicationContext;
private ReferenceBeanManager referenceBeanManager;
private BeanDefinitionRegistry beanDefinitionRegistry;
@Nullable
private ConfigurableListableBeanFactory beanFactory;
/**
* {@link com.alibaba.dubbo.config.annotation.Reference @com.alibaba.dubbo.config.annotation.Reference} has been supported since 2.7.3
* <p>
* {@link DubboReference @DubboReference} has been supported since 2.7.7
*/
public ReferenceAnnotationWithAotBeanPostProcessor() {
super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
Class<?> beanType;
if (beanFactory.isFactoryBean(beanName)) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (isReferenceBean(beanDefinition)) {
continue;
}
if (isAnnotatedReferenceBean(beanDefinition)) {
// process @DubboReference at java-config @bean method
processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);
continue;
}
String beanClassName = beanDefinition.getBeanClassName();
beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());
} else {
beanType = beanFactory.getType(beanName);
}
if (beanType != null) {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
try {
prepareInjection(metadata);
} catch (BeansException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
// if (beanFactory instanceof AbstractBeanFactory) {
// List<BeanPostProcessor> beanPostProcessors = ((AbstractBeanFactory) beanFactory).getBeanPostProcessors();
// for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
// if (beanPostProcessor == this) {
// // This bean has been registered as BeanPostProcessor at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()
// // so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause BeanPostProcessorChecker detection error
// beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME);
// break;
// }
// }
// }
try {
// this is an early event, it will be notified at org.springframework.context.support.AbstractApplicationContext.registerListeners()
applicationContext.publishEvent(new DubboConfigInitEvent(applicationContext));
} catch (Exception e) {
// if spring version is less than 4.2, it does not support early application event
logger.warn(CONFIG_DUBBO_BEAN_INITIALIZER, "", "", "publish early application event failed, please upgrade spring version to 4.2.x or later: " + e);
}
}
/**
* check whether is @DubboReference at java-config @bean method
*/
private boolean isAnnotatedReferenceBean(BeanDefinition beanDefinition) {
if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
String beanClassName = SpringCompatUtils.getFactoryMethodReturnType(annotatedBeanDefinition);
if (beanClassName != null && ReferenceBean.class.getName().equals(beanClassName)) {
return true;
}
}
return false;
}
/**
* process @DubboReference at java-config @bean method
* <pre class="code">
* &#064;Configuration
* public class ConsumerConfig {
*
* &#064;Bean
* &#064;DubboReference(group="demo", version="1.2.3")
* public ReferenceBean&lt;DemoService&gt; demoService() {
* return new ReferenceBean();
* }
*
* }
* </pre>
*
* @param beanName
* @param beanDefinition
*/
private void processReferenceAnnotatedBeanDefinition(String beanName, AnnotatedBeanDefinition beanDefinition) {
MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(beanDefinition);
// 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);
if (beanClass == Object.class) {
beanClass = SpringCompatUtils.getGenericTypeOfReturnType(factoryMethodMetadata);
}
if (beanClass == Object.class) {
// bean class is invalid, ignore it
return;
}
if (beanClass == null) {
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, " +
"such as ReferenceBean<DemoService>. Please check bean method: " + beanMethodSignature);
}
// get dubbo reference annotation attributes
Map<String, Object> annotationAttributes = null;
// try all dubbo reference annotation types
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
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);
break;
}
}
if (annotationAttributes != null) {
// @DubboReference on @Bean method
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>(annotationAttributes);
// reset id attribute
attributes.put(ReferenceAttributes.ID, beanName);
// convert annotation props
ReferenceBeanSupport.convertReferenceProps(attributes, beanClass);
// get interface
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
// check beanClass and reference interface class
if (!StringUtils.isEquals(interfaceName, beanClass.getName()) && beanClass != GenericService.class) {
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. " +
"The interface class of @DubboReference is: " + interfaceName + ", but return ReferenceBean<" + beanClass.getName() + ">. " +
"Please remove the 'interfaceClass' and 'interfaceName' attributes from @DubboReference annotation. " +
"Please check bean method: " + beanMethodSignature);
}
Class interfaceClass = beanClass;
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
} else {
// raw reference bean
// the ReferenceBean is not yet initialized
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, beanClass);
if (beanClass != GenericService.class) {
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, beanClass.getName());
}
}
// set id
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, beanName);
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
if (isReferenceBean(beanDefinition)) {
//mark property value as optional
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();
for (PropertyValue propertyValue : propertyValues) {
propertyValue.setOptional(true);
}
} else if (isAnnotatedReferenceBean(beanDefinition)) {
// extract beanClass from java-config bean method generic return type: ReferenceBean<DemoService>
//Class beanClass = getBeanFactory().getType(beanName);
} else {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
try {
prepareInjection(metadata);
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
}
/**
* Alternatives to the {@link #postProcessProperties(PropertyValues, Object, String)}, that removed as of Spring
* Framework 6.0.0, and in favor of {@link #postProcessProperties(PropertyValues, Object, String)}.
* <p>In order to be compatible with the lower version of Spring, it is still retained.
*
* @see #postProcessProperties
*/
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return postProcessProperties(pvs, bean, beanName);
}
/**
* Alternatives to the {@link #postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)}.
*
* @see #postProcessPropertyValues
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
try {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
prepareInjection(metadata);
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
private boolean isReferenceBean(BeanDefinition beanDefinition) {
return ReferenceBean.class.getName().equals(beanDefinition.getBeanClassName());
}
@Override
@Nullable
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
String beanName = registeredBean.getBeanName();
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanDefinition, beanClass, beanName);
if (!CollectionUtils.isEmpty(metadata.getFieldElements()) || !CollectionUtils.isEmpty(metadata.getMethodElements())) {
return new AotContribution(beanClass, metadata, getAutowireCandidateResolver());
}
return null;
}
private AnnotatedInjectionMetadata findInjectionMetadata(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
return metadata;
}
protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {
try {
//find and register bean definition for @DubboReference/@Reference
for (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {
if (fieldElement.injectedObject != null) {
continue;
}
Class<?> injectedType = fieldElement.field.getType();
AnnotationAttributes attributes = fieldElement.attributes;
String referenceBeanName = registerReferenceBean(fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);
//associate fieldElement and reference bean
fieldElement.injectedObject = referenceBeanName;
injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);
}
for (AnnotatedMethodElement methodElement : metadata.getMethodElements()) {
if (methodElement.injectedObject != null) {
continue;
}
Class<?> injectedType = methodElement.getInjectedType();
AnnotationAttributes attributes = methodElement.attributes;
String referenceBeanName = registerReferenceBean(methodElement.getPropertyName(), injectedType, attributes, methodElement.method);
//associate methodElement and reference bean
methodElement.injectedObject = referenceBeanName;
injectedMethodReferenceBeanCache.put(methodElement, referenceBeanName);
}
} catch (ClassNotFoundException e) {
throw new BeanCreationException("prepare reference annotation failed", e);
}
}
public String registerReferenceBean(String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member) throws BeansException {
boolean renameable = true;
// referenceBeanName
String referenceBeanName = getAttribute(attributes, ReferenceAttributes.ID);
if (hasText(referenceBeanName)) {
renameable = false;
} else {
referenceBeanName = propertyName;
}
String checkLocation = "Please check " + member.toString();
// convert annotation props
ReferenceBeanSupport.convertReferenceProps(attributes, injectedType);
// get interface
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
if (StringUtils.isBlank(interfaceName)) {
throw new BeanCreationException("Need to specify the 'interfaceName' or 'interfaceClass' attribute of '@DubboReference' if enable generic. " + checkLocation);
}
// check reference key
String referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext);
// find reference bean name by reference key
List<String> registeredReferenceBeanNames = referenceBeanManager.getBeanNamesByKey(referenceKey);
if (registeredReferenceBeanNames.size() > 0) {
// found same name and reference key
if (registeredReferenceBeanNames.contains(referenceBeanName)) {
return referenceBeanName;
}
}
//check bean definition
boolean isContains;
if ((isContains = beanDefinitionRegistry.containsBeanDefinition(referenceBeanName)) || beanDefinitionRegistry.isAlias(referenceBeanName)) {
String preReferenceBeanName = referenceBeanName;
if (!isContains) {
// Look in the alias for the origin bean name
String[] aliases = beanDefinitionRegistry.getAliases(referenceBeanName);
if (ArrayUtils.isNotEmpty(aliases)) {
for (String alias : aliases) {
if (beanDefinitionRegistry.containsBeanDefinition(alias)) {
preReferenceBeanName = alias;
break;
}
}
}
}
BeanDefinition prevBeanDefinition = beanDefinitionRegistry.getBeanDefinition(preReferenceBeanName);
String prevBeanType = prevBeanDefinition.getBeanClassName();
String prevBeanDesc = referenceBeanName + "[" + prevBeanType + "]";
String newBeanDesc = referenceBeanName + "[" + referenceKey + "]";
if (isReferenceBean(prevBeanDefinition)) {
//check reference key
String prevReferenceKey = ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext);
if (StringUtils.isEquals(prevReferenceKey, referenceKey)) {
//found matched dubbo reference bean, ignore register
return referenceBeanName;
}
//get interfaceName from attribute
Assert.notNull(prevBeanDefinition, "The interface class of ReferenceBean is not initialized");
prevBeanDesc = referenceBeanName + "[" + prevReferenceKey + "]";
}
// bean name from attribute 'id' or java-config bean, cannot be renamed
if (!renameable) {
throw new BeanCreationException("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
"but cannot rename the reference bean name (specify the id attribute or java-config bean), " +
"please modify the name of one of the beans: " +
"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
}
// the prev bean type is different, rename the new reference bean
int index = 2;
String newReferenceBeanName = null;
while (newReferenceBeanName == null || beanDefinitionRegistry.containsBeanDefinition(newReferenceBeanName)
|| beanDefinitionRegistry.isAlias(newReferenceBeanName)) {
newReferenceBeanName = referenceBeanName + "#" + index;
index++;
// double check found same name and reference key
if (registeredReferenceBeanNames.contains(newReferenceBeanName)) {
return newReferenceBeanName;
}
}
newBeanDesc = newReferenceBeanName + "[" + referenceKey + "]";
logger.warn(CONFIG_DUBBO_BEAN_INITIALIZER, "", "", "Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
"rename dubbo reference bean to [" + newReferenceBeanName + "]. " +
"It is recommended to modify the name of one of the beans to avoid injection problems. " +
"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
referenceBeanName = newReferenceBeanName;
}
attributes.put(ReferenceAttributes.ID, referenceBeanName);
// If registered matched reference before, just register alias
if (registeredReferenceBeanNames.size() > 0) {
beanDefinitionRegistry.registerAlias(registeredReferenceBeanNames.get(0), referenceBeanName);
referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
return referenceBeanName;
}
Class interfaceClass = injectedType;
// TODO Only register one reference bean for same (group, interface, version)
// Register the reference bean definition to the beanFactory
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(ReferenceBean.class.getName());
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// beanDefinition.getPropertyValues().add(Constants.REFERENCE_PROPS,attributes);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean
// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()
GenericBeanDefinition targetDefinition = new GenericBeanDefinition();
targetDefinition.setBeanClass(interfaceClass);
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, referenceBeanName + "_decorated"));
// signal object type since Spring 5.2
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
logger.info("Register dubbo reference bean: " + referenceBeanName + " = " + referenceKey + " at " + member);
return referenceBeanName;
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
if (injectedElement.injectedObject == null) {
throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");
}
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.referenceBeanManager = applicationContext.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
this.beanDefinitionRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
}
@Override
public void destroy() throws Exception {
super.destroy();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
/**
* Gets all beans of {@link ReferenceBean}
*
* @deprecated use {@link ReferenceBeanManager#getReferences()} instead
*/
@Deprecated
public Collection<ReferenceBean<?>> getReferenceBeans() {
return Collections.emptyList();
}
/**
* Get {@link ReferenceBean} {@link Map} in injected field.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();
for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedFieldReferenceBeanCache.entrySet()) {
map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));
}
return Collections.unmodifiableMap(map);
}
/**
* Get {@link ReferenceBean} {@link Map} in injected method.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();
for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedMethodReferenceBeanCache.entrySet()) {
map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));
}
return Collections.unmodifiableMap(map);
}
@Nullable
private AutowireCandidateResolver getAutowireCandidateResolver() {
if (this.beanFactory instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory) this.beanFactory).getAutowireCandidateResolver();
}
return null;
}
private static class AotContribution implements BeanRegistrationAotContribution {
private static final String REGISTERED_BEAN_PARAMETER = "registeredBean";
private static final String INSTANCE_PARAMETER = "instance";
private final Class<?> target;
private final AnnotatedInjectionMetadata annotatedInjectionMetadata;
@Nullable
private final AutowireCandidateResolver candidateResolver;
AotContribution(Class<?> target, AnnotatedInjectionMetadata annotatedInjectionMetadata, AutowireCandidateResolver candidateResolver) {
this.target = target;
this.annotatedInjectionMetadata = annotatedInjectionMetadata;
this.candidateResolver = candidateResolver;
}
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
.addForFeatureComponent("DubboReference", this.target, type -> {
type.addJavadoc("DubboReference for {@link $T}.", this.target);
type.addModifiers(javax.lang.model.element.Modifier.PUBLIC);
});
GeneratedMethod generateMethod = generatedClass.getMethods().add("apply", method -> {
method.addJavadoc("Apply the dubbo reference.");
method.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
javax.lang.model.element.Modifier.STATIC);
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
method.addParameter(this.target, INSTANCE_PARAMETER);
method.returns(this.target);
method.addCode(generateMethodCode(generatedClass.getName(),
generationContext.getRuntimeHints()));
});
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
if (this.candidateResolver != null) {
registerHints(generationContext.getRuntimeHints());
}
}
private CodeBlock generateMethodCode(ClassName targetClassName, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getFieldElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getFieldElements()) {
code.addStatement(generateMethodStatementForElement(
targetClassName, referenceElement, hints));
}
}
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getMethodElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getMethodElements()) {
code.addStatement(generateMethodStatementForElement(
targetClassName, referenceElement, hints));
}
}
code.addStatement("return $L", INSTANCE_PARAMETER);
return code.build();
}
private CodeBlock generateMethodStatementForElement(ClassName targetClassName,
AnnotatedInjectElement referenceElement, RuntimeHints hints) {
Member member = referenceElement.getMember();
AnnotationAttributes attributes = referenceElement.attributes;
Object injectedObject = referenceElement.injectedObject;
try {
Class<?> c = referenceElement.getInjectedType();
hints.reflection().registerType(TypeReference.of(c), MemberCategory.INVOKE_PUBLIC_METHODS);
hints.proxies().registerJdkProxy(c, EchoService.class, Destroyable.class);
hints.proxies().registerJdkProxy(c, EchoService.class, Destroyable.class, SpringProxy.class, Advised.class, DecoratingProxy.class);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (member instanceof Field) {
return generateMethodStatementForField(
targetClassName, (Field) member, attributes, injectedObject, hints);
}
if (member instanceof Method) {
return generateMethodStatementForMethod(
targetClassName, (Method) member, attributes, injectedObject, hints);
}
throw new IllegalStateException(
"Unsupported member type " + member.getClass().getName());
}
private CodeBlock generateMethodStatementForField(ClassName targetClassName,
Field field, AnnotationAttributes attributes, Object injectedObject, RuntimeHints hints) {
hints.reflection().registerField(field);
CodeBlock resolver = CodeBlock.of("$T.$L($S)",
ReferencedFieldValueResolver.class,
"forRequiredField", field.getName());
CodeBlock shortcutResolver = CodeBlock.of("$L.withShortcut($S)", resolver, injectedObject);
AccessControl accessControl = AccessControl.forMember(field);
if (!accessControl.isAccessibleFrom(targetClassName)) {
return CodeBlock.of("$L.resolveAndSet($L, $L)", shortcutResolver,
REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
}
return CodeBlock.of("$L.$L = $L.resolve($L)", INSTANCE_PARAMETER,
field.getName(), shortcutResolver, REGISTERED_BEAN_PARAMETER);
}
private CodeBlock generateMethodStatementForMethod(ClassName targetClassName,
Method method, AnnotationAttributes attributes, Object injectedObject, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
code.add("$T.$L", ReferencedMethodArgumentsResolver.class, "forRequiredMethod");
code.add("($S", method.getName());
if (method.getParameterCount() > 0) {
code.add(", $L", generateParameterTypesCode(method.getParameterTypes()));
}
code.add(")");
if (method.getParameterCount() > 0) {
Parameter[] parameters = method.getParameters();
String[] parameterNames = new String[parameters.length];
for (int i = 0; i < parameterNames.length; i++) {
parameterNames[i] = parameters[i].getName();
}
code.add(".withShortcut($L)", generateParameterNamesCode(parameterNames));
}
AccessControl accessControl = AccessControl.forMember(method);
if (!accessControl.isAccessibleFrom(targetClassName)) {
hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
code.add(".resolveAndInvoke($L, $L)", REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
} else {
hints.reflection().registerMethod(method, ExecutableMode.INTROSPECT);
CodeBlock arguments = new AutowiredArgumentsCodeGenerator(this.target,
method).generateCode(method.getParameterTypes());
CodeBlock injectionCode = CodeBlock.of("args -> $L.$L($L)",
INSTANCE_PARAMETER, method.getName(), arguments);
code.add(".resolve($L, $L)", REGISTERED_BEAN_PARAMETER, injectionCode);
}
return code.build();
}
private CodeBlock generateParameterNamesCode(String[] parameterNames) {
CodeBlock.Builder code = CodeBlock.builder();
for (int i = 0; i < parameterNames.length; i++) {
code.add(i != 0 ? ", " : "");
code.add("$S", parameterNames[i]);
}
return code.build();
}
private CodeBlock generateParameterTypesCode(Class<?>[] parameterTypes) {
CodeBlock.Builder code = CodeBlock.builder();
for (int i = 0; i < parameterTypes.length; i++) {
code.add(i != 0 ? ", " : "");
code.add("$T.class", parameterTypes[i]);
}
return code.build();
}
private void registerHints(RuntimeHints runtimeHints) {
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getFieldElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getFieldElements()) {
Member member = referenceElement.getMember();
if (member instanceof Field) {
Field field = (Field) member;
DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, true);
registerProxyIfNecessary(runtimeHints, dependencyDescriptor);
}
}
}
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getMethodElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getMethodElements()) {
Member member = referenceElement.getMember();
if (member instanceof Method) {
Method method = (Method) member;
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(methodParam, true);
registerProxyIfNecessary(runtimeHints, dependencyDescriptor);
}
}
}
}
}
private void registerProxyIfNecessary(RuntimeHints runtimeHints, DependencyDescriptor dependencyDescriptor) {
if (this.candidateResolver != null) {
Class<?> proxyClass =
this.candidateResolver.getLazyResolutionProxyClass(dependencyDescriptor, null);
if (proxyClass != null) {
ClassHintUtils.registerProxyIfNecessary(proxyClass, runtimeHints);
}
}
}
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.spring6.beans.factory.annotation;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import java.util.Collection;
/**
* 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 &lt;dubbo:annotation /&gt;
*
* @see AnnotationBeanDefinitionParser
* @see BeanDefinitionRegistryPostProcessor
* @since 3.2
*/
public class ServiceAnnotationWithAotPostProcessor extends ServiceAnnotationPostProcessor implements BeanRegistrationAotProcessor {
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
public ServiceAnnotationWithAotPostProcessor(String... packagesToScan) {
super(packagesToScan);
}
public ServiceAnnotationWithAotPostProcessor(Collection<?> packagesToScan) {
super(packagesToScan);
}
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
if (beanClass.equals(ServiceBean.class)) {
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
String interfaceName = (String) beanDefinition.getPropertyValues().get("interface");
try {
Class<?> c = Class.forName(interfaceName);
return new DubboServiceBeanRegistrationAotContribution(c);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else if (servicePackagesHolder.isClassScanned(beanClass.getName())) {
return new DubboServiceBeanRegistrationAotContribution(beanClass);
}
return null;
}
private static class DubboServiceBeanRegistrationAotContribution implements BeanRegistrationAotContribution {
private final Class<?> cl;
public DubboServiceBeanRegistrationAotContribution(Class<?> cl) {
this.cl = cl;
}
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
generationContext.getRuntimeHints().reflection().registerType(TypeReference.of(cl),
MemberCategory.INVOKE_PUBLIC_METHODS);
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.spring6.beans.factory.aot;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.log.LogMessage;
import javax.lang.model.element.Element;
import java.util.Set;
/**
* Base class for resolvers that support autowiring related to an
* {@link Element}.
*/
abstract class AutowiredElementResolver {
private final Log logger = LogFactory.getLog(getClass());
protected final void registerDependentBeans(ConfigurableBeanFactory beanFactory,
String beanName, Set<String> autowiredBeanNames) {
for (String autowiredBeanName : autowiredBeanNames) {
if (beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, beanName);
}
logger.trace(LogMessage.format(
"Autowiring by type from bean name %s' to bean named '%s'", beanName,
autowiredBeanName));
}
}
/**
* {@link DependencyDescriptor} that supports shortcut bean resolution.
*/
@SuppressWarnings("serial")
static class ShortcutDependencyDescriptor extends DependencyDescriptor {
private final String shortcut;
private final Class<?> requiredType;
public ShortcutDependencyDescriptor(DependencyDescriptor original,
String shortcut, Class<?> requiredType) {
super(original);
this.shortcut = shortcut;
this.requiredType = requiredType;
}
@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return beanFactory.getBean(this.shortcut, this.requiredType);
}
}
}

View File

@ -0,0 +1,216 @@
/*
* 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.spring6.beans.factory.aot;
import org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.function.ThrowingConsumer;
import java.lang.reflect.Field;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Resolver used to support the autowiring of fields. Typically used in
* AOT-processed applications as a targeted alternative to the
* {@link ReferenceAnnotationWithAotBeanPostProcessor
* ReferenceAnnotationBeanPostProcessor}.
*
* <p>When resolving arguments in a native image, the {@link Field} being used must
* be marked with an {@link ExecutableMode#INTROSPECT introspection} hint so
* that field annotations can be read. Full {@link ExecutableMode#INVOKE
* invocation} hints are only required if the
* {@link #resolveAndSet(RegisteredBean, Object)} method of this class is being
* used (typically to support private fields).
*/
public final class ReferencedFieldValueResolver extends AutowiredElementResolver {
private final String fieldName;
private final boolean required;
@Nullable
private final String shortcut;
private ReferencedFieldValueResolver(String fieldName, boolean required,
@Nullable String shortcut) {
Assert.hasText(fieldName, "'fieldName' must not be empty");
this.fieldName = fieldName;
this.required = required;
this.shortcut = shortcut;
}
/**
* Create a new {@link ReferencedFieldValueResolver} for the specified field
* where injection is optional.
*
* @param fieldName the field name
* @return a new {@link ReferencedFieldValueResolver} instance
*/
public static ReferencedFieldValueResolver forField(String fieldName) {
return new ReferencedFieldValueResolver(fieldName, false, null);
}
/**
* Create a new {@link ReferencedFieldValueResolver} for the specified field
* where injection is required.
*
* @param fieldName the field name
* @return a new {@link ReferencedFieldValueResolver} instance
*/
public static ReferencedFieldValueResolver forRequiredField(String fieldName) {
return new ReferencedFieldValueResolver(fieldName, true, null);
}
/**
* Return a new {@link ReferencedFieldValueResolver} instance that uses a
* direct bean name injection shortcut.
*
* @param beanName the bean name to use as a shortcut
* @return a new {@link ReferencedFieldValueResolver} instance that uses the
* shortcuts
*/
public ReferencedFieldValueResolver withShortcut(String beanName) {
return new ReferencedFieldValueResolver(this.fieldName, this.required, beanName);
}
/**
* Resolve the field for the specified registered bean and provide it to the
* given action.
*
* @param registeredBean the registered bean
* @param action the action to execute with the resolved field value
*/
public <T> void resolve(RegisteredBean registeredBean, ThrowingConsumer<T> action) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
Assert.notNull(action, "'action' must not be null");
T resolved = resolve(registeredBean);
if (resolved != null) {
action.accept(resolved);
}
}
/**
* Resolve the field value for the specified registered bean.
*
* @param registeredBean the registered bean
* @param requiredType the required type
* @return the resolved field value
*/
@Nullable
@SuppressWarnings("unchecked")
public <T> T resolve(RegisteredBean registeredBean, Class<T> requiredType) {
Object value = resolveObject(registeredBean);
Assert.isInstanceOf(requiredType, value);
return (T) value;
}
/**
* Resolve the field value for the specified registered bean.
*
* @param registeredBean the registered bean
* @return the resolved field value
*/
@Nullable
@SuppressWarnings("unchecked")
public <T> T resolve(RegisteredBean registeredBean) {
return (T) resolveObject(registeredBean);
}
/**
* Resolve the field value for the specified registered bean.
*
* @param registeredBean the registered bean
* @return the resolved field value
*/
@Nullable
public Object resolveObject(RegisteredBean registeredBean) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
return resolveValue(registeredBean, getField(registeredBean));
}
/**
* Resolve the field value for the specified registered bean and set it
* using reflection.
*
* @param registeredBean the registered bean
* @param instance the bean instance
*/
public void resolveAndSet(RegisteredBean registeredBean, Object instance) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
Assert.notNull(instance, "'instance' must not be null");
Field field = getField(registeredBean);
Object resolved = resolveValue(registeredBean, field);
if (resolved != null) {
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, instance, resolved);
}
}
@Nullable
private Object resolveValue(RegisteredBean registeredBean, Field field) {
String beanName = registeredBean.getBeanName();
Class<?> beanClass = registeredBean.getBeanClass();
ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
descriptor.setContainingClass(beanClass);
if (this.shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut,
field.getType());
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);
Object injectedObject = beanFactory.getBean(shortcut);
Object value = ((AutowireCapableBeanFactory) beanFactory).resolveDependency(
descriptor, beanName, autowiredBeanNames, typeConverter);
registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
return injectedObject;
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName,
new InjectionPoint(field), ex);
}
}
private Field getField(RegisteredBean registeredBean) {
Field field = ReflectionUtils.findField(registeredBean.getBeanClass(),
this.fieldName);
Assert.notNull(field, () -> "No field '" + this.fieldName + "' found on "
+ registeredBean.getBeanClass().getName());
return field;
}
}

View File

@ -0,0 +1,221 @@
/*
* 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.spring6.beans.factory.aot;
import org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.aot.AutowiredArguments;
import org.springframework.beans.factory.aot.AutowiredFieldValueResolver;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.function.ThrowingConsumer;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Resolver used to support the autowiring of methods. Typically used in
* AOT-processed applications as a targeted alternative to the
* {@link ReferenceAnnotationWithAotBeanPostProcessor
* ReferenceAnnotationBeanPostProcessor}.
*
* <p>When resolving arguments in a native image, the {@link Method} being used
* must be marked with an {@link ExecutableMode#INTROSPECT introspection} hint
* so that field annotations can be read. Full {@link ExecutableMode#INVOKE
* invocation} hints are only required if the
* {@link #resolveAndInvoke(RegisteredBean, Object)} method of this class is
* being used (typically to support private methods).
*/
public final class ReferencedMethodArgumentsResolver extends AutowiredElementResolver {
private final String methodName;
private final Class<?>[] parameterTypes;
private final boolean required;
@Nullable
private final String[] shortcuts;
private ReferencedMethodArgumentsResolver(String methodName, Class<?>[] parameterTypes,
boolean required, @Nullable String[] shortcuts) {
Assert.hasText(methodName, "'methodName' must not be empty");
this.methodName = methodName;
this.parameterTypes = parameterTypes;
this.required = required;
this.shortcuts = shortcuts;
}
/**
* Create a new {@link ReferencedMethodArgumentsResolver} for the specified
* method where injection is optional.
*
* @param methodName the method name
* @param parameterTypes the factory method parameter types
* @return a new {@link org.springframework.beans.factory.aot.AutowiredFieldValueResolver} instance
*/
public static ReferencedMethodArgumentsResolver forMethod(String methodName,
Class<?>... parameterTypes) {
return new ReferencedMethodArgumentsResolver(methodName, parameterTypes, false,
null);
}
/**
* Create a new {@link ReferencedMethodArgumentsResolver} for the specified
* method where injection is required.
*
* @param methodName the method name
* @param parameterTypes the factory method parameter types
* @return a new {@link AutowiredFieldValueResolver} instance
*/
public static ReferencedMethodArgumentsResolver forRequiredMethod(String methodName,
Class<?>... parameterTypes) {
return new ReferencedMethodArgumentsResolver(methodName, parameterTypes, true,
null);
}
/**
* Return a new {@link ReferencedMethodArgumentsResolver} instance
* that uses direct bean name injection shortcuts for specific parameters.
*
* @param beanNames the bean names to use as shortcuts (aligned with the
* method parameters)
* @return a new {@link ReferencedMethodArgumentsResolver} instance that uses
* the shortcuts
*/
public ReferencedMethodArgumentsResolver withShortcut(String... beanNames) {
return new ReferencedMethodArgumentsResolver(this.methodName, this.parameterTypes,
this.required, beanNames);
}
/**
* Resolve the method arguments for the specified registered bean and
* provide it to the given action.
*
* @param registeredBean the registered bean
* @param action the action to execute with the resolved method arguments
*/
public void resolve(RegisteredBean registeredBean,
ThrowingConsumer<AutowiredArguments> action) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
Assert.notNull(action, "'action' must not be null");
AutowiredArguments resolved = resolve(registeredBean);
if (resolved != null) {
action.accept(resolved);
}
}
/**
* Resolve the method arguments for the specified registered bean.
*
* @param registeredBean the registered bean
* @return the resolved method arguments
*/
@Nullable
public AutowiredArguments resolve(RegisteredBean registeredBean) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
return resolveArguments(registeredBean, getMethod(registeredBean));
}
/**
* Resolve the method arguments for the specified registered bean and invoke
* the method using reflection.
*
* @param registeredBean the registered bean
* @param instance the bean instance
*/
public void resolveAndInvoke(RegisteredBean registeredBean, Object instance) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
Assert.notNull(instance, "'instance' must not be null");
Method method = getMethod(registeredBean);
AutowiredArguments resolved = resolveArguments(registeredBean, method);
if (resolved != null) {
ReflectionUtils.makeAccessible(method);
ReflectionUtils.invokeMethod(method, instance, resolved.toArray());
}
}
@Nullable
private AutowiredArguments resolveArguments(RegisteredBean registeredBean,
Method method) {
String beanName = registeredBean.getBeanName();
Class<?> beanClass = registeredBean.getBeanClass();
ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();
Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);
AutowireCapableBeanFactory autowireCapableBeanFactory = (AutowireCapableBeanFactory) beanFactory;
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
Set<String> autowiredBeanNames = new LinkedHashSet<>(argumentCount);
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < argumentCount; i++) {
MethodParameter parameter = new MethodParameter(method, i);
DependencyDescriptor descriptor = new DependencyDescriptor(parameter,
this.required);
descriptor.setContainingClass(beanClass);
String shortcut = (this.shortcuts != null) ? this.shortcuts[i] : null;
if (shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut,
parameter.getParameterType());
}
try {
Object injectedArgument = beanFactory.getBean(shortcut);
Object argument = autowireCapableBeanFactory.resolveDependency(descriptor,
beanName, autowiredBeanNames, typeConverter);
arguments[i] = injectedArgument;
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName,
new InjectionPoint(parameter), ex);
}
}
registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
return AutowiredArguments.of(arguments);
}
private Method getMethod(RegisteredBean registeredBean) {
Method method = ReflectionUtils.findMethod(registeredBean.getBeanClass(),
this.methodName, this.parameterTypes);
Assert.notNull(method, () ->
"Method '" + this.methodName + "' with parameter types [" + toCommaSeparatedNames(this.parameterTypes) + "] declared on " + registeredBean.getBeanClass().getName() + " could not be found.");
return method;
}
private String toCommaSeparatedNames(Class<?>... parameterTypes) {
return Arrays.stream(parameterTypes).map(Class::getName)
.collect(Collectors.joining(", "));
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.spring6.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
/**
* Register some infrastructure beans if not exists.
* This post-processor MUST impl BeanDefinitionRegistryPostProcessor,
* in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.
*
* @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(
*ConfigurableListableBeanFactory, java.util.List)
*/
public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}

View File

@ -32,6 +32,7 @@
<modules>
<module>dubbo-config-api</module>
<module>dubbo-config-spring</module>
<module>dubbo-config-spring6</module>
</modules>
<dependencies>

View File

@ -1315,6 +1315,34 @@
</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar
</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/dubbo/internal/org.apache.dubbo.aot.api.ProxyDescriberRegistrar
</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/dubbo/internal/org.apache.dubbo.aot.api.ResourceDescriberRegistrar
</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/dubbo/internal/org.apache.dubbo.common.json.JsonUtil
</resource>
</transformer>
</transformers>
<filters>
<filter>

View File

@ -78,6 +78,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring6</artifactId>
<version>${project.version}</version>
</dependency>
<!-- config-center -->
<dependency>
<groupId>org.apache.dubbo</groupId>

View File

@ -85,6 +85,12 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,43 @@
/*
* 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.metadata.aot;
import org.apache.dubbo.aot.api.JdkProxyDescriber;
import org.apache.dubbo.aot.api.ProxyDescriberRegistrar;
import org.apache.dubbo.metadata.MetadataService;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import java.util.ArrayList;
import java.util.List;
public class MetadataProxyDescriberRegistrar implements ProxyDescriberRegistrar {
@Override
public List<JdkProxyDescriber> getJdkProxyDescribers() {
List<JdkProxyDescriber> describers = new ArrayList<>();
describers.add(buildJdkProxyDescriber(MetadataService.class));
return describers;
}
private JdkProxyDescriber buildJdkProxyDescriber(Class<?> cl) {
List<String> proxiedInterfaces = new ArrayList<>();
proxiedInterfaces.add(cl.getName());
proxiedInterfaces.add(EchoService.class.getName());
proxiedInterfaces.add(Destroyable.class.getName());
return new JdkProxyDescriber(proxiedInterfaces, null);
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.metadata.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.metadata.MetadataService;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MetadataReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithPublicMethod(MetadataService.class));
typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(MetadataInfo.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithPublicMethod(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
metadata=org.apache.dubbo.metadata.aot.MetadataProxyDescriberRegistrar

View File

@ -0,0 +1 @@
metadata=org.apache.dubbo.metadata.aot.MetadataReflectionTypeDescriberRegistrar

View File

@ -36,6 +36,13 @@
<artifactId>dubbo-metrics-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-test</artifactId>

View File

@ -0,0 +1,43 @@
/*
* 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.metrics.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.metrics.collector.HistogramMetricsCollector;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DefaultMetricsReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(HistogramMetricsCollector.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
defaultMetrics=org.apache.dubbo.metrics.aot.DefaultMetricsReflectionTypeDescriberRegistrar

View File

@ -0,0 +1,3 @@
default=org.apache.dubbo.metrics.collector.DefaultMetricsCollector
aggregateMetricsCollector=org.apache.dubbo.metrics.collector.AggregateMetricsCollector
configCenterMetricsCollector=org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
/**
* A describer that describes the conditions for the configuration to take effect.

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.lang.reflect.Executable;

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.lang.reflect.Field;

View File

@ -0,0 +1,62 @@
/*
* 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.aot.api;
import java.util.List;
import java.util.Objects;
/**
* A describer that describes the need for a JDK interface-based {@link java.lang.reflect.Proxy}.
*/
public class JdkProxyDescriber implements ConditionalDescriber {
private final List<String> proxiedInterfaces;
private final String reachableType;
public JdkProxyDescriber(List<String> proxiedInterfaces, String reachableType) {
this.proxiedInterfaces = proxiedInterfaces;
this.reachableType = reachableType;
}
public List<String> getProxiedInterfaces() {
return proxiedInterfaces;
}
@Override
public String getReachableType() {
return reachableType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
JdkProxyDescriber that = (JdkProxyDescriber) o;
return Objects.equals(proxiedInterfaces, that.proxiedInterfaces) && Objects.equals(reachableType, that.reachableType);
}
@Override
public int hashCode() {
return Objects.hash(proxiedInterfaces, reachableType);
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.lang.reflect.Member;

View File

@ -0,0 +1,26 @@
/*
* 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.aot.api;
import org.apache.dubbo.common.extension.SPI;
import java.util.List;
@SPI
public interface ProxyDescriberRegistrar {
List<JdkProxyDescriber> getJdkProxyDescribers();
}

View File

@ -0,0 +1,26 @@
/*
* 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.aot.api;
import org.apache.dubbo.common.extension.SPI;
import java.util.List;
@SPI
public interface ReflectionTypeDescriberRegistrar {
List<TypeDescriber> getTypeDescribers();
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.util.List;
import java.util.Objects;

View File

@ -0,0 +1,28 @@
/*
* 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.aot.api;
import org.apache.dubbo.common.extension.SPI;
import java.util.List;
@SPI
public interface ResourceDescriberRegistrar {
List<ResourcePatternDescriber> getResourcePatternDescribers();
List<ResourceBundleDescriber> getResourceBundleDescribers();
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import java.util.Arrays;
import java.util.regex.Pattern;

View File

@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.aot.generate;
package org.apache.dubbo.aot.api;
import org.apache.dubbo.aot.generate.ExecutableDescriber;
import java.util.Set;

View File

@ -16,6 +16,12 @@
*/
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.JdkProxyDescriber;
import org.apache.dubbo.aot.api.ProxyDescriberRegistrar;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.rpc.model.FrameworkModel;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@ -44,10 +50,31 @@ public class AotProcessor {
.registerSpiExtensionType(new ArrayList<>(ClassSourceScanner.INSTANCE.distinctSpiExtensionClasses(ResourceScanner.INSTANCE.distinctSpiResource()).values()))
.registerAdaptiveType(new ArrayList<>(ClassSourceScanner.INSTANCE.adaptiveClasses().values()))
.registerBeanType(ClassSourceScanner.INSTANCE.scopeModelInitializer())
.registerConfigType(ClassSourceScanner.INSTANCE.configClasses());
.registerConfigType(ClassSourceScanner.INSTANCE.configClasses())
.registerTypeDescriber(getTypes());
writer.writeReflectionConfig(reflectRepository);
ProxyConfigMetadataRepository proxyRepository = new ProxyConfigMetadataRepository();
proxyRepository.registerProxyDescribers(getProxyDescribers());
writer.writeProxyConfig(proxyRepository);
}
private static List<TypeDescriber> getTypes() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
FrameworkModel.defaultModel().defaultApplication().getExtensionLoader(ReflectionTypeDescriberRegistrar.class).getSupportedExtensionInstances().forEach(reflectionTypeDescriberRegistrar -> {
typeDescribers.addAll(reflectionTypeDescriberRegistrar.getTypeDescribers());
});
return typeDescribers;
}
private static List<JdkProxyDescriber> getProxyDescribers() {
List<JdkProxyDescriber> jdkProxyDescribers = new ArrayList<>();
FrameworkModel.defaultModel().defaultApplication().getExtensionLoader(ProxyDescriberRegistrar.class).getSupportedExtensionInstances().forEach(reflectionTypeDescriberRegistrar -> {
jdkProxyDescribers.addAll(reflectionTypeDescriberRegistrar.getJdkProxyDescribers());
});
return jdkProxyDescribers;
}

View File

@ -17,6 +17,9 @@
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.ExecutableMode;
import org.apache.dubbo.aot.api.MemberDescriber;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.util.Arrays;

View File

@ -93,7 +93,6 @@ public class JarScanner {
File[] listFiles = directory.listFiles();
if (listFiles != null) {
for (File file : listFiles) {
System.out.println("scanFile: " + file.getPath());
if (file.isDirectory()) {
scanFile(file.getPath());
} else {

View File

@ -27,6 +27,7 @@ import java.util.function.Consumer;
* Write Write configuration metadata information in
* {@link ResourceConfigMetadataRepository} and {@link ReflectConfigMetadataRepository}
* as GraalVM native configuration.
*
* @see <a href="https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildConfiguration/">Native Image Build Configuration</a>
*/
public class NativeConfigurationWriter {
@ -49,8 +50,7 @@ public class NativeConfigurationWriter {
try (FileWriter out = new FileWriter(file)) {
writer.accept(createJsonWriter(out));
}
}
catch (IOException ex) {
} catch (IOException ex) {
throw new IllegalStateException("Failed to write native configuration for " + fileName, ex);
}
}
@ -58,7 +58,7 @@ public class NativeConfigurationWriter {
private File createIfNecessary(String filename) throws IOException {
Path outputDirectory = this.basePath.resolve("META-INF").resolve("native-image");
if (this.groupId != null && this.artifactId != null) {
outputDirectory = outputDirectory.resolve(this.groupId).resolve(this.artifactId);
outputDirectory = outputDirectory.resolve(this.groupId).resolve(this.artifactId).resolve("dubbo");
}
outputDirectory.toFile().mkdirs();
File file = outputDirectory.resolve(filename).toFile();
@ -77,6 +77,11 @@ public class NativeConfigurationWriter {
ResourceConfigWriter.INSTANCE.write(writer, repository));
}
public void writeProxyConfig(ProxyConfigMetadataRepository repository) {
writeTo("proxy-config.json", writer ->
ProxyConfigWriter.INSTANCE.write(writer, repository));
}
private BasicJsonWriter createJsonWriter(Writer out) {
return new BasicJsonWriter(out);
}

View File

@ -0,0 +1,50 @@
/*
* 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.aot.generate;
import org.apache.dubbo.aot.api.JdkProxyDescriber;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class ProxyConfigMetadataRepository {
private final Set<JdkProxyDescriber> jdkProxyDescribers;
public ProxyConfigMetadataRepository() {
this.jdkProxyDescribers = new LinkedHashSet<>();
}
public ProxyConfigMetadataRepository registerProxyDescriber(JdkProxyDescriber describer) {
this.jdkProxyDescribers.add(describer);
return this;
}
public ProxyConfigMetadataRepository registerProxyDescribers(List<JdkProxyDescriber> describers) {
this.jdkProxyDescribers.addAll(describers.stream().filter(Objects::nonNull).collect(Collectors.toList()));
return this;
}
public Set<JdkProxyDescriber> getProxyDescribers() {
return jdkProxyDescribers;
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.aot.generate;
import org.apache.dubbo.aot.api.JdkProxyDescriber;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Write a {@link ProxyConfigMetadataRepository} to the JSON output expected by the GraalVM
* {@code native-image} compiler, typically named {@code proxy-config.json}.
*/
public class ProxyConfigWriter {
public static final ProxyConfigWriter INSTANCE = new ProxyConfigWriter();
public void write(BasicJsonWriter writer, ProxyConfigMetadataRepository repository) {
writer.writeArray(repository.getProxyDescribers().stream().map(this::toAttributes).collect(Collectors.toList()));
}
private Map<String, Object> toAttributes(JdkProxyDescriber describer) {
Map<String, Object> attributes = new LinkedHashMap<>();
handleCondition(attributes, describer);
attributes.put("interfaces", describer.getProxiedInterfaces());
return attributes;
}
private void handleCondition(Map<String, Object> attributes, JdkProxyDescriber describer) {
if (describer.getReachableType() != null) {
Map<String, Object> conditionAttributes = new LinkedHashMap<>();
conditionAttributes.put("typeReachable", describer.getReachableType());
attributes.put("condition", conditionAttributes);
}
}
}

View File

@ -16,6 +16,9 @@
*/
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.TypeDescriber;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@ -24,7 +27,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.dubbo.aot.generate.ExecutableMode.INVOKE;
import static org.apache.dubbo.aot.api.ExecutableMode.INVOKE;
public class ReflectConfigMetadataRepository {
@ -34,22 +37,22 @@ public class ReflectConfigMetadataRepository {
this.types = new ArrayList<>();
}
public ReflectConfigMetadataRepository registerSpiExtensionType(List<Class<?>> classes) {
protected ReflectConfigMetadataRepository registerSpiExtensionType(List<Class<?>> classes) {
types.addAll(classes.stream().filter(Objects::nonNull).map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
return this;
}
public ReflectConfigMetadataRepository registerAdaptiveType(List<Class<?>> classes) {
protected ReflectConfigMetadataRepository registerAdaptiveType(List<Class<?>> classes) {
types.addAll(classes.stream().filter(Objects::nonNull).map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
return this;
}
public ReflectConfigMetadataRepository registerBeanType(List<Class<?>> classes) {
protected ReflectConfigMetadataRepository registerBeanType(List<Class<?>> classes) {
types.addAll(classes.stream().filter(Objects::nonNull).map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
return this;
}
public ReflectConfigMetadataRepository registerConfigType(List<Class<?>> classes) {
protected ReflectConfigMetadataRepository registerConfigType(List<Class<?>> classes) {
types.addAll(classes.stream().filter(Objects::nonNull).map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
return this;
}
@ -61,6 +64,10 @@ public class ReflectConfigMetadataRepository {
return new TypeDescriber(c.getName(), null, new HashSet<>(), constructors, new HashSet<>(), memberCategories);
}
public void registerTypeDescriber(List<TypeDescriber> typeDescribers) {
types.addAll(typeDescribers.stream().filter(Objects::nonNull).collect(Collectors.toList()));
}
public List<TypeDescriber> getTypes() {
return types;
}

View File

@ -16,6 +16,11 @@
*/
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.ExecutableMode;
import org.apache.dubbo.aot.api.FieldDescriber;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.TypeDescriber;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

View File

@ -17,6 +17,9 @@
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.ResourceBundleDescriber;
import org.apache.dubbo.aot.api.ResourcePatternDescriber;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

View File

@ -16,6 +16,10 @@
*/
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.ConditionalDescriber;
import org.apache.dubbo.aot.api.ResourceBundleDescriber;
import org.apache.dubbo.aot.api.ResourcePatternDescriber;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.aot.generate;
import org.apache.dubbo.aot.api.ResourcePatternDescriber;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

View File

@ -75,5 +75,11 @@
<artifactId>dubbo-qos-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,44 @@
/*
* 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.qos.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import java.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class QosReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithPublicMethod(SelectorProvider.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithPublicMethod(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
qos=org.apache.dubbo.qos.aot.QosReflectionTypeDescriberRegistrar

View File

@ -105,5 +105,11 @@
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.registry;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;
import org.apache.dubbo.registry.support.RegistryManager;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
@ -33,6 +34,7 @@ public class RegistryScopeModelInitializer implements ScopeModelInitializer {
public void initializeApplicationModel(ApplicationModel applicationModel) {
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
beanFactory.registerBean(RegistryManager.class);
beanFactory.registerBean(MetadataServiceDelegation.class);
}
@Override

View File

@ -0,0 +1,46 @@
/*
* 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.registry.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class RegistryReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclaredMethod(MetadataServiceDelegation.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclaredMethod(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.registry.client.metadata;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
@ -141,6 +142,10 @@ public class MetadataUtils {
url = url.setServiceModel(consumerModel);
if (NativeDetector.inNativeImage()) {
url = url.addParameter("proxy", "jdk");
}
Invoker<MetadataService> invoker = protocol.refer(MetadataService.class, url);
ProxyFactory proxyFactory = applicationModel.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

View File

@ -0,0 +1 @@
registry=org.apache.dubbo.registry.aot.RegistryReflectionTypeDescriberRegistrar

View File

@ -0,0 +1,47 @@
/*
* 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.registry.zookeeper.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.registry.zookeeper.ZookeeperInstance;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ZookeeperReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclared(ZookeeperInstance.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclared(Class<?> cl) {
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
memberCategories.add(MemberCategory.DECLARED_FIELDS);
return new TypeDescriber(cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
zookeeper=org.apache.dubbo.registry.zookeeper.aot.ZookeeperReflectionTypeDescriberRegistrar

View File

@ -69,5 +69,11 @@
<classifier>linux-aarch_64</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,50 @@
/*
* 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.remoting.transport.netty4.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.dubbo.remoting.transport.netty4.NettyClientHandler;
import org.apache.dubbo.remoting.transport.netty4.NettyServerHandler;
import org.apache.dubbo.remoting.transport.netty4.ssl.SslClientTlsHandler;
import org.apache.dubbo.remoting.transport.netty4.ssl.SslServerTlsHandler;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Netty4ReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclaredMethods(NettyServerHandler.class));
typeDescribers.add(buildTypeDescriberWithDeclaredMethods(SslServerTlsHandler.class));
typeDescribers.add(buildTypeDescriberWithDeclaredMethods(NettyClientHandler.class));
typeDescribers.add(buildTypeDescriberWithDeclaredMethods(SslClientTlsHandler.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclaredMethods(Class<?> c){
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);
return new TypeDescriber(c.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
netty4=org.apache.dubbo.remoting.transport.netty4.aot.Netty4ReflectionTypeDescriberRegistrar

View File

@ -59,5 +59,11 @@
<artifactId>zookeeper</artifactId>
<version>${zookeeper_version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,54 @@
/*
* 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.remoting.zookeeper.curator5.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.zookeeper.ClientCnxnSocketNIO;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Curator5ZookeeperReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(ClientCnxnSocketNIO.class));
typeDescribers.add(buildTypeDescriberWithDeclared("org.apache.curator.x.discovery.ServiceInstance"));
typeDescribers.add(buildTypeDescriberWithDeclared("org.apache.curator.x.discovery.details.OldServiceInstance"));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclared(String className){
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
memberCategories.add(MemberCategory.DECLARED_FIELDS);
return new TypeDescriber(className, null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> c){
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return new TypeDescriber(c.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
curator5Zookeeper=org.apache.dubbo.remoting.zookeeper.curator5.aot.Curator5ZookeeperReflectionTypeDescriberRegistrar

View File

@ -57,6 +57,13 @@
<artifactId>curator-x-discovery</artifactId>
<version>${curator_version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-native</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>

View File

@ -0,0 +1,50 @@
/*
* 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.remoting.zookeeper.curator.aot;
import org.apache.dubbo.aot.api.MemberCategory;
import org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;
import org.apache.dubbo.aot.api.TypeDescriber;
import org.apache.zookeeper.ClientCnxnSocketNIO;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CuratorZookeeperReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {
@Override
public List<TypeDescriber> getTypeDescribers() {
List<TypeDescriber> typeDescribers = new ArrayList<>();
typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(ClientCnxnSocketNIO.class));
return typeDescribers;
}
private TypeDescriber buildTypeDescriberWithDeclaredMethods(Class<?> c){
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);
return new TypeDescriber(c.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> c){
Set<MemberCategory> memberCategories = new HashSet<>();
memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return new TypeDescriber(c.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);
}
}

View File

@ -0,0 +1 @@
curatorZookeeper=org.apache.dubbo.remoting.zookeeper.curator.aot.CuratorZookeeperReflectionTypeDescriberRegistrar

View File

@ -16,6 +16,9 @@
*/
package org.apache.dubbo.common.serialize.fastjson2;
import com.alibaba.fastjson2.reader.ObjectReaderCreator;
import com.alibaba.fastjson2.writer.ObjectWriterCreator;
import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.ScopeClassLoaderListener;
@ -31,10 +34,11 @@ public class Fastjson2CreatorManager implements ScopeClassLoaderListener<Framewo
/**
* An empty classLoader used when classLoader is system classLoader. Prevent the NPE.
*/
private static final ClassLoader SYSTEM_CLASSLOADER_KEY = new ClassLoader() {};
private static final ClassLoader SYSTEM_CLASSLOADER_KEY = new ClassLoader() {
};
private final Map<ClassLoader, ObjectReaderCreatorASM> readerMap = new ConcurrentHashMap<>();
private final Map<ClassLoader, ObjectWriterCreatorASM> writerMap = new ConcurrentHashMap<>();
private final Map<ClassLoader, ObjectReaderCreator> readerMap = new ConcurrentHashMap<>();
private final Map<ClassLoader, ObjectWriterCreator> writerMap = new ConcurrentHashMap<>();
public Fastjson2CreatorManager(FrameworkModel frameworkModel) {
frameworkModel.addClassLoaderListener(this);
@ -44,8 +48,13 @@ public class Fastjson2CreatorManager implements ScopeClassLoaderListener<Framewo
if (classLoader == null) {
classLoader = SYSTEM_CLASSLOADER_KEY;
}
JSONFactory.setContextReaderCreator(readerMap.computeIfAbsent(classLoader, ObjectReaderCreatorASM::new));
JSONFactory.setContextWriterCreator(writerMap.computeIfAbsent(classLoader, ObjectWriterCreatorASM::new));
if (NativeDetector.inNativeImage()) {
JSONFactory.setContextReaderCreator(readerMap.putIfAbsent(classLoader, ObjectReaderCreator.INSTANCE));
JSONFactory.setContextWriterCreator(writerMap.putIfAbsent(classLoader, ObjectWriterCreator.INSTANCE));
} else {
JSONFactory.setContextReaderCreator(readerMap.computeIfAbsent(classLoader, ObjectReaderCreatorASM::new));
JSONFactory.setContextWriterCreator(writerMap.computeIfAbsent(classLoader, ObjectWriterCreatorASM::new));
}
}
@Override

View File

@ -21,7 +21,7 @@ import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -30,6 +30,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collection;
import java.util.Set;
import static org.apache.dubbo.spring.boot.util.DubboUtils.BASE_PACKAGES_BEAN_NAME;
@ -63,8 +64,14 @@ public class DubboAutoConfiguration {
@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
@Bean
public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
Set<String> packagesToScan) {
return new ServiceAnnotationPostProcessor(packagesToScan);
Set<String> packagesToScan) {
ServiceAnnotationPostProcessor serviceAnnotationPostProcessor;
try {
serviceAnnotationPostProcessor = (ServiceAnnotationPostProcessor) SpringCompatUtils.serviceAnnotationPostProcessor().getDeclaredConstructor(Collection.class).newInstance(packagesToScan);
} catch (Exception e) {
throw new RuntimeException(e);
}
return serviceAnnotationPostProcessor;
}
}

View File

@ -19,7 +19,6 @@ package org.apache.dubbo.spring.boot.autoconfigure;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -20,7 +20,6 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;

View File

@ -66,6 +66,10 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring6</artifactId>
</dependency>
<!-- config-center -->
<dependency>

View File

@ -54,6 +54,7 @@ class FileTest {
ignoredArtifacts.add(Pattern.compile("dubbo-demo.*"));
ignoredArtifacts.add(Pattern.compile("dubbo-test.*"));
ignoredArtifacts.add(Pattern.compile("dubbo-config-spring6.*"));
ignoredArtifacts.add(Pattern.compile("dubbo-annotation-processor"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo"));
@ -63,6 +64,7 @@ class FileTest {
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-distribution"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-metadata-processor"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-native.*"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-config-spring6.*"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-spring-boot.*"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-annotation-processor.*"));
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-maven-plugin"));

View File

@ -345,8 +345,8 @@
**/org/apache/dubbo/maven/plugin/aot/RunArguments.java,
**/org/apache/dubbo/maven/plugin/aot/RunProcess.java,
**/org/apache/dubbo/aot/generate/BasicJsonWriter.java,
**/org/apache/dubbo/aot/generate/ExecutableMode.java,
**/org/apache/dubbo/aot/generate/MemberCategory.java,
**/org/apache/dubbo/aot/api/ExecutableMode.java,
**/org/apache/dubbo/aot/api/MemberCategory.java,
**/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java,
**/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java,
**/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java,