diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java index dc05557f20..91c1c9ddd9 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java @@ -21,10 +21,10 @@ import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.filter.DemoService; -import org.apache.dubbo.rpc.RpcException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -56,6 +56,7 @@ class FailSafeClusterInvokerTest { @BeforeEach public void setUp() throws Exception { + RpcContext.removeServiceContext(); dic = mock(Directory.class); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java index ed161d7c79..bbc17745fc 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java @@ -24,10 +24,10 @@ import org.apache.dubbo.common.utils.LogUtil; import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.cluster.Directory; import org.apache.log4j.Level; import org.junit.jupiter.api.AfterEach; @@ -38,7 +38,6 @@ import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.function.Executable; import java.lang.reflect.Field; import java.util.ArrayList; @@ -47,7 +46,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -72,6 +71,7 @@ class FailbackClusterInvokerTest { @BeforeEach public void setUp() throws Exception { + RpcContext.removeServiceContext(); dic = mock(Directory.class); given(dic.getUrl()).willReturn(url); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java index 8bb3bbfe51..8163b2b0b1 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java @@ -145,6 +145,10 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy { if (!guard.tryAcquire()) { return; } + // To avoid multiple dump, check again + if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) { + return; + } ExecutorService pool = Executors.newSingleThreadExecutor(); pool.execute(() -> { @@ -169,9 +173,9 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy { } catch (Exception t) { logger.error(COMMON_UNEXPECTED_CREATE_DUMP, "", "", "dump jStack error", t); } finally { + lastPrintTime = System.currentTimeMillis(); guard.release(); } - lastPrintTime = System.currentTimeMillis(); }); //must shutdown thread pool ,if not will lead to OOM pool.shutdown(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java index 3faa74f012..95fb31b366 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java @@ -109,6 +109,12 @@ public class MetricsConfig extends AbstractConfig { private Boolean enableRpc; + /** + * The level of the metrics, the value can be "SERVICE", "METHOD", default is method. + */ + private String rpcLevel; + + public MetricsConfig() { } @@ -139,6 +145,14 @@ public class MetricsConfig extends AbstractConfig { return enableJvm; } + public String getRpcLevel() { + return rpcLevel; + } + + public void setRpcLevel(String rpcLevel) { + this.rpcLevel = rpcLevel; + } + public void setEnableJvm(Boolean enableJvm) { this.enableJvm = enableJvm; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 92fae4a971..a3af6e4943 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -40,6 +40,7 @@ import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metadata.ServiceNameMapping; import org.apache.dubbo.metrics.event.MetricsEventBus; import org.apache.dubbo.metrics.event.MetricsInitEvent; +import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.registry.client.metadata.MetadataUtils; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; @@ -560,11 +561,12 @@ public class ServiceConfig extends ServiceConfigBase { } private void initServiceMethodMetrics(URL url) { - String [] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i->i.split(",")).orElse( new String[]{}); - Arrays.stream(methods).forEach( method-> { - RpcInvocation invocation = new RpcInvocation(url.getServiceKey(),url.getServiceModel(),method,interfaceName, url.getProtocolServiceKey(), null, null,null,null,null,null); - MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(),invocation)); - }); + String[] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i -> i.split(",")).orElse(new String[]{}); + boolean serviceLevel = MethodMetric.isServiceLevel(application.getApplicationModel()); + Arrays.stream(methods).forEach(method -> { + RpcInvocation invocation = new RpcInvocation(url.getServiceKey(), url.getServiceModel(), method, interfaceName, url.getProtocolServiceKey(), null, null, null, null, null, null); + MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(), invocation, serviceLevel)); + }); } private void processServiceExecutor(URL url) { diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index 8874cdbd9b..7477b12ecc 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -1120,6 +1120,11 @@ + + + + + diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml index 17b4bb654f..1eabccca2a 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml @@ -224,7 +224,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.25 + 0.9.27 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml index ac2943a2bf..32aa0f0f5b 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml @@ -222,7 +222,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.25 + 0.9.27 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/pom.xml index bfe8fc9334..a50275da63 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml @@ -38,7 +38,7 @@ true 2.7.15 2.7.15 - 1.11.3 + 1.11.4 diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 03c36be9dd..b796d48520 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -94,7 +94,7 @@ 5.3.25 5.8.6 3.29.2-GA - 1.14.7 + 1.14.8 3.2.10.Final 4.1.97.Final 2.2.1 @@ -114,7 +114,7 @@ 3.5.5 0.19.0 4.0.66 - 3.24.2 + 3.24.3 1.3.2 3.1.0 9.4.52.v20230823 @@ -133,14 +133,14 @@ 3.12.0 1.8.0 0.1.35 - 1.11.3 + 1.11.4 1.26.0 2.16.4 - 1.1.4 + 1.1.5 3.3 0.16.0 1.0.4 - 3.5.9 + 3.5.10 2.2.21 3.14.9 @@ -152,7 +152,7 @@ 2.2.4 1.8.6 1.6.1 - 1.57.2 + 1.58.0 0.8.1 1.2.2 diff --git a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java index 7cd13982e1..ab742d3561 100644 --- a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java +++ b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.validation.filter; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.ConfigUtils; import org.apache.dubbo.rpc.AsyncRpcResult; @@ -82,8 +83,7 @@ public class ValidationFilter implements Filter { */ @Override public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - if (validation != null && !invocation.getMethodName().startsWith("$") - && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) { + if (needValidate(invoker.getUrl(), invocation.getMethodName())) { try { Validator validator = validation.getValidator(invoker.getUrl()); if (validator != null) { @@ -98,4 +98,8 @@ public class ValidationFilter implements Filter { return invoker.invoke(invocation); } + private boolean needValidate(URL url, String methodName) { + return validation != null && !methodName.startsWith("$") && ConfigUtils.isNotEmpty(url.getMethodParameter(methodName, VALIDATION_KEY)); + } + } diff --git a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java index 7051ab2176..b55fb9a0d9 100644 --- a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java +++ b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ReflectUtils; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.validation.MethodValidated; import org.apache.dubbo.validation.Validator; @@ -57,6 +58,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -89,7 +91,7 @@ public class JValidator implements Validator { this.clazz = ReflectUtils.forName(url.getServiceInterface()); String jvalidation = url.getParameter("jvalidation"); ValidatorFactory factory; - if (jvalidation != null && jvalidation.length() > 0) { + if (StringUtils.isNotEmpty(jvalidation)) { factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory(); } else { factory = Validation.buildDefaultValidatorFactory(); @@ -111,8 +113,9 @@ public class JValidator implements Validator { parameterClass = generateMethodParameterClass(clazz, method, parameterClassName); } Object parameterBean = parameterClass.getDeclaredConstructor().newInstance(); - for (int i = 0; i < args.length; i++) { - Field field = parameterClass.getField(method.getName() + "Argument" + i); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Field field = parameterClass.getField(parameters[i].getName()); field.set(parameterBean, args[i]); } return parameterBean; @@ -129,10 +132,9 @@ public class JValidator implements Validator { * @param method invoke method * @param parameterClassName generated parameterClassName * @return Class generated methodParameterClass - * @throws Exception */ private static Class generateMethodParameterClass(Class clazz, Method method, String parameterClassName) - throws Exception { + throws Exception { ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader()); synchronized (parameterClassName.intern()) { CtClass ctClass = null; @@ -144,28 +146,26 @@ public class JValidator implements Validator { if (null == ctClass) { ctClass = pool.makeClass(parameterClassName); ClassFile classFile = ctClass.getClassFile(); - classFile.setVersionToJava5(); ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName))); // parameter fields - Class[] parameterTypes = method.getParameterTypes(); + Parameter[] parameters = method.getParameters(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - for (int i = 0; i < parameterTypes.length; i++) { - Class type = parameterTypes[i]; + for (int i = 0; i < parameters.length; i++) { Annotation[] annotations = parameterAnnotations[i]; AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag); for (Annotation annotation : annotations) { if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation( - classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName())); + classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName())); Method[] members = annotation.annotationType().getMethods(); for (Method member : members) { if (Modifier.isPublic(member.getModifiers()) - && member.getParameterTypes().length == 0 - && member.getDeclaringClass() == annotation.annotationType()) { + && member.getParameterTypes().length == 0 + && member.getDeclaringClass() == annotation.annotationType()) { Object value = member.invoke(annotation); if (null != value) { MemberValue memberValue = createMemberValue( - classFile.getConstPool(), pool.get(member.getReturnType().getName()), value); + classFile.getConstPool(), pool.get(member.getReturnType().getName()), value); ja.addMemberValue(member.getName(), memberValue); } } @@ -173,12 +173,14 @@ public class JValidator implements Validator { attribute.addAnnotation(ja); } } - String fieldName = method.getName() + "Argument" + i; + Parameter parameter = parameters[i]; + Class type = parameter.getType(); + String fieldName = parameter.getName(); CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName)); ctField.getFieldInfo().addAttribute(attribute); ctClass.addField(ctField); } - return ctClass.toClass(clazz.getClassLoader(), null); + return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain()); } else { return Class.forName(parameterClassName, true, clazz.getClassLoader()); } @@ -187,13 +189,16 @@ public class JValidator implements Validator { private static String generateMethodParameterClassName(Class clazz, Method method) { StringBuilder builder = new StringBuilder().append(clazz.getName()) - .append('_') - .append(toUpperMethoName(method.getName())) - .append("Parameter"); + .append('_') + .append(toUpperMethodName(method.getName())) + .append("Parameter"); Class[] parameterTypes = method.getParameterTypes(); for (Class parameterType : parameterTypes) { - builder.append('_').append(parameterType.getName()); + // In order to ensure that the parameter class can be generated correctly, + // replace "." with "_" to make the package name of the generated parameter class + // consistent with the package name of the actual parameter class. + builder.append('_').append(parameterType.getName().replace(".", "_")); } return builder.toString(); @@ -201,19 +206,17 @@ public class JValidator implements Validator { private static boolean hasConstraintParameter(Method method) { Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - if (parameterAnnotations != null && parameterAnnotations.length > 0) { - for (Annotation[] annotations : parameterAnnotations) { - for (Annotation annotation : annotations) { - if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { - return true; - } + for (Annotation[] annotations : parameterAnnotations) { + for (Annotation annotation : annotations) { + if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { + return true; } } } return false; } - private static String toUpperMethoName(String methodName) { + private static String toUpperMethodName(String methodName) { return methodName.substring(0, 1).toUpperCase() + methodName.substring(1); } @@ -263,7 +266,7 @@ public class JValidator implements Validator { if (methodClass != null) { groups.add(methodClass); } - Set> violations = new HashSet<>(); + Method method = clazz.getMethod(methodName, parameterTypes); Class[] methodClasses; if (method.isAnnotationPresent(MethodValidated.class)) { @@ -275,15 +278,16 @@ public class JValidator implements Validator { groups.add(1, clazz); // convert list to array - Class[] classgroups = groups.toArray(new Class[groups.size()]); + Class[] classGroups = groups.toArray(new Class[0]); + Set> violations = new HashSet<>(); Object parameterBean = getMethodParameterBean(clazz, method, arguments); if (parameterBean != null) { - violations.addAll(validator.validate(parameterBean, classgroups)); + violations.addAll(validator.validate(parameterBean, classGroups)); } for (Object arg : arguments) { - validate(violations, arg, classgroups); + validate(violations, arg, classGroups); } if (!violations.isEmpty()) { @@ -294,7 +298,7 @@ public class JValidator implements Validator { private Class methodClass(String methodName) { Class methodClass = null; - String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName); + String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName); Class cached = methodClassMap.get(methodClassName); if (cached != null) { return cached == clazz ? null : cached; diff --git a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidatorNew.java b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidatorNew.java index fca479c76f..b217131c82 100644 --- a/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidatorNew.java +++ b/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidatorNew.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ReflectUtils; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.validation.MethodValidated; import org.apache.dubbo.validation.Validator; @@ -57,6 +58,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -89,7 +91,7 @@ public class JValidatorNew implements Validator { this.clazz = ReflectUtils.forName(url.getServiceInterface()); String jvalidation = url.getParameter("jvalidationNew"); ValidatorFactory factory; - if (jvalidation != null && jvalidation.length() > 0) { + if (StringUtils.isNotEmpty(jvalidation)) { factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory(); } else { factory = Validation.buildDefaultValidatorFactory(); @@ -111,8 +113,9 @@ public class JValidatorNew implements Validator { parameterClass = generateMethodParameterClass(clazz, method, parameterClassName); } Object parameterBean = parameterClass.getDeclaredConstructor().newInstance(); - for (int i = 0; i < args.length; i++) { - Field field = parameterClass.getField(method.getName() + "Argument" + i); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Field field = parameterClass.getField(parameters[i].getName()); field.set(parameterBean, args[i]); } return parameterBean; @@ -129,10 +132,9 @@ public class JValidatorNew implements Validator { * @param method invoke method * @param parameterClassName generated parameterClassName * @return Class generated methodParameterClass - * @throws Exception */ private static Class generateMethodParameterClass(Class clazz, Method method, String parameterClassName) - throws Exception { + throws Exception { ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader()); synchronized (parameterClassName.intern()) { CtClass ctClass = null; @@ -144,28 +146,26 @@ public class JValidatorNew implements Validator { if (null == ctClass) { ctClass = pool.makeClass(parameterClassName); ClassFile classFile = ctClass.getClassFile(); - classFile.setVersionToJava5(); ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName))); // parameter fields - Class[] parameterTypes = method.getParameterTypes(); + Parameter[] parameters = method.getParameters(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - for (int i = 0; i < parameterTypes.length; i++) { - Class type = parameterTypes[i]; + for (int i = 0; i < parameters.length; i++) { Annotation[] annotations = parameterAnnotations[i]; AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag); for (Annotation annotation : annotations) { if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation( - classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName())); + classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName())); Method[] members = annotation.annotationType().getMethods(); for (Method member : members) { if (Modifier.isPublic(member.getModifiers()) - && member.getParameterTypes().length == 0 - && member.getDeclaringClass() == annotation.annotationType()) { + && member.getParameterTypes().length == 0 + && member.getDeclaringClass() == annotation.annotationType()) { Object value = member.invoke(annotation); if (null != value) { MemberValue memberValue = createMemberValue( - classFile.getConstPool(), pool.get(member.getReturnType().getName()), value); + classFile.getConstPool(), pool.get(member.getReturnType().getName()), value); ja.addMemberValue(member.getName(), memberValue); } } @@ -173,12 +173,14 @@ public class JValidatorNew implements Validator { attribute.addAnnotation(ja); } } - String fieldName = method.getName() + "Argument" + i; + Parameter parameter = parameters[i]; + Class type = parameter.getType(); + String fieldName = parameter.getName(); CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName)); ctField.getFieldInfo().addAttribute(attribute); ctClass.addField(ctField); } - return ctClass.toClass(clazz.getClassLoader(), null); + return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain()); } else { return Class.forName(parameterClassName, true, clazz.getClassLoader()); } @@ -187,13 +189,16 @@ public class JValidatorNew implements Validator { private static String generateMethodParameterClassName(Class clazz, Method method) { StringBuilder builder = new StringBuilder().append(clazz.getName()) - .append('_') - .append(toUpperMethoName(method.getName())) - .append("Parameter"); + .append('_') + .append(toUpperMethodName(method.getName())) + .append("Parameter"); Class[] parameterTypes = method.getParameterTypes(); for (Class parameterType : parameterTypes) { - builder.append('_').append(parameterType.getName()); + // In order to ensure that the parameter class can be generated correctly, + // replace "." with "_" to make the package name of the generated parameter class + // consistent with the package name of the actual parameter class. + builder.append('_').append(parameterType.getName().replace(".", "_")); } return builder.toString(); @@ -201,19 +206,17 @@ public class JValidatorNew implements Validator { private static boolean hasConstraintParameter(Method method) { Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - if (parameterAnnotations.length > 0) { - for (Annotation[] annotations : parameterAnnotations) { - for (Annotation annotation : annotations) { - if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { - return true; - } + for (Annotation[] annotations : parameterAnnotations) { + for (Annotation annotation : annotations) { + if (annotation.annotationType().isAnnotationPresent(Constraint.class)) { + return true; } } } return false; } - private static String toUpperMethoName(String methodName) { + private static String toUpperMethodName(String methodName) { return methodName.substring(0, 1).toUpperCase() + methodName.substring(1); } @@ -263,7 +266,7 @@ public class JValidatorNew implements Validator { if (methodClass != null) { groups.add(methodClass); } - Set> violations = new HashSet<>(); + Method method = clazz.getMethod(methodName, parameterTypes); Class[] methodClasses; if (method.isAnnotationPresent(MethodValidated.class)) { @@ -275,15 +278,16 @@ public class JValidatorNew implements Validator { groups.add(1, clazz); // convert list to array - Class[] classgroups = groups.toArray(new Class[groups.size()]); + Class[] classGroups = groups.toArray(new Class[0]); + Set> violations = new HashSet<>(); Object parameterBean = getMethodParameterBean(clazz, method, arguments); if (parameterBean != null) { - violations.addAll(validator.validate(parameterBean, classgroups)); + violations.addAll(validator.validate(parameterBean, classGroups)); } for (Object arg : arguments) { - validate(violations, arg, classgroups); + validate(violations, arg, classGroups); } if (!violations.isEmpty()) { @@ -294,7 +298,7 @@ public class JValidatorNew implements Validator { private Class methodClass(String methodName) { Class methodClass = null; - String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName); + String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName); Class cached = methodClassMap.get(methodClassName); if (cached != null) { return cached == clazz ? null : cached; diff --git a/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidatorTest.java b/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidatorTest.java index 0f04dafd6e..a434b6d7dd 100644 --- a/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidatorTest.java +++ b/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidatorTest.java @@ -17,17 +17,24 @@ package org.apache.dubbo.validation.support.jvalidation; import org.apache.dubbo.common.URL; +import org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget; import org.apache.dubbo.validation.support.jvalidation.mock.ValidationParameter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import javax.validation.ConstraintViolationException; import javax.validation.ValidationException; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + class JValidatorTest { @Test void testItWithNonExistMethod() { @@ -72,7 +79,7 @@ class JValidatorTest { void testItWithCollectionArg() throws Exception { URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); JValidator jValidator = new JValidator(url); - jValidator.validate("someMethod4", new Class[]{List.class}, new Object[]{Arrays.asList("parameter")}); + jValidator.validate("someMethod4", new Class[]{List.class}, new Object[]{Collections.singletonList("parameter")}); } @Test @@ -83,4 +90,83 @@ class JValidatorTest { map.put("key", "value"); jValidator.validate("someMethod5", new Class[]{Map.class}, new Object[]{map}); } -} \ No newline at end of file + + @Test + void testItWithPrimitiveArg() { + Assertions.assertThrows(ValidationException.class, () -> { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + jValidator.validate("someMethod6", new Class[]{Integer.class, String.class, Long.class}, new Object[]{null, null, null}); + }); + } + + @Test + void testItWithPrimitiveArgWithProvidedMessage() { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + try { + jValidator.validate("someMethod6", new Class[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null}); + Assertions.fail(); + } catch (Exception e) { + assertThat(e.getMessage(), containsString("string must not be blank")); + assertThat(e.getMessage(), containsString("longValue must not be null")); + } + } + + @Test + void testItWithPartialParameterValidation() { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + try { + jValidator.validate("someMethod6", new Class[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null}); + Assertions.fail(); + } catch (Exception e) { + assertThat(e, instanceOf(ConstraintViolationException.class)); + ConstraintViolationException e1 = (ConstraintViolationException) e; + assertThat(e1.getConstraintViolations().size(), is(2)); + } + } + + @Test + void testItWithNestedParameterValidationWithNullParam() { + Assertions.assertThrows(ValidationException.class, () -> { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + jValidator.validate("someMethod7", new Class[]{JValidatorTestTarget.BaseParam.class}, new Object[]{null}); + }); + } + + @Test + void testItWithNestedParameterValidationWithNullNestedParam() { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + try { + JValidatorTestTarget.BaseParam param = new JValidatorTestTarget.BaseParam<>(); + jValidator.validate("someMethod7", new Class[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param}); + Assertions.fail(); + } catch (Exception e) { + assertThat(e, instanceOf(ConstraintViolationException.class)); + ConstraintViolationException e1 = (ConstraintViolationException) e; + assertThat(e1.getConstraintViolations().size(), is(1)); + assertThat(e1.getMessage(), containsString("body must not be null")); + } + } + + @Test + void testItWithNestedParameterValidationWithNullNestedParams() { + URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget"); + JValidator jValidator = new JValidator(url); + try { + JValidatorTestTarget.BaseParam param = new JValidatorTestTarget.BaseParam<>(); + param.setBody(new JValidatorTestTarget.Param()); + jValidator.validate("someMethod7", new Class[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param}); + Assertions.fail(); + } catch (Exception e) { + assertThat(e, instanceOf(ConstraintViolationException.class)); + ConstraintViolationException e1 = (ConstraintViolationException) e; + assertThat(e1.getConstraintViolations().size(), is(1)); + assertThat(e1.getMessage(), containsString("name must not be null")); + } + } + +} diff --git a/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/JValidatorTestTarget.java b/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/JValidatorTestTarget.java index f65eb0573d..9cf5dec6f3 100644 --- a/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/JValidatorTestTarget.java +++ b/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/JValidatorTestTarget.java @@ -18,6 +18,9 @@ package org.apache.dubbo.validation.support.jvalidation.mock; import org.apache.dubbo.validation.MethodValidated; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.Valid; import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; @@ -35,7 +38,42 @@ public interface JValidatorTestTarget { void someMethod5(Map map); + void someMethod6(Integer intValue, + @NotBlank(message = "string must not be blank") String string, + @NotNull(message = "longValue must not be null") Long longValue); + + void someMethod7(@NotNull BaseParam baseParam); + @interface Test2 { } + class BaseParam { + + @Valid + @NotNull(message = "body must not be null") + private T body; + + public T getBody() { + return body; + } + + public void setBody(T body) { + this.body = body; + } + } + + class Param { + + @NotNull(message = "name must not be null") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounter.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounter.java index 32f4e63235..8cf70c7fed 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounter.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounter.java @@ -28,7 +28,7 @@ public class TimeWindowCounter { private final LongAdderSlidingWindow slidingWindow; - public TimeWindowCounter(int bucketNum, int timeWindowSeconds) { + public TimeWindowCounter(int bucketNum, long timeWindowSeconds) { this.slidingWindow = new LongAdderSlidingWindow(bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds)); } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java index d6cba3ee50..06cd8ade6e 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java @@ -41,9 +41,11 @@ import java.util.concurrent.atomic.AtomicLong; * the key will not be displayed when exporting (to be optimized) */ public class MethodStatComposite extends AbstractMetricsExport { + private boolean serviceLevel; public MethodStatComposite(ApplicationModel applicationModel) { super(applicationModel); + this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel()); } private final Map> methodNumStats = new ConcurrentHashMap<>(); @@ -59,7 +61,8 @@ public class MethodStatComposite extends AbstractMetricsExport { if (!methodNumStats.containsKey(wrapper)) { return; } - methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation), k -> new AtomicLong(0L)); + + methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation, serviceLevel), k -> new AtomicLong(0L)); } public void incrementMethodKey(MetricsKeyWrapper wrapper, MethodMetric methodMetric, int size) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java index e6d0bae6e7..d335c0dfba 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java @@ -50,9 +50,11 @@ import java.util.stream.Collectors; */ @SuppressWarnings({"rawtypes", "unchecked"}) public class RtStatComposite extends AbstractMetricsExport { + private boolean serviceLevel; public RtStatComposite(ApplicationModel applicationModel) { super(applicationModel); + this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel()); } private final Map>> rtStats = new ConcurrentHashMap<>(); @@ -168,7 +170,7 @@ public class RtStatComposite extends AbstractMetricsExport { List actions; actions = new LinkedList<>(); for (LongContainer container : rtStats.get(registryOpType)) { - MethodMetric key = new MethodMetric(getApplicationModel(), invocation); + MethodMetric key = new MethodMetric(getApplicationModel(), invocation, serviceLevel); Number current = (Number) container.get(key); if (current == null) { container.putIfAbsent(key, container.getInitFunc().apply(key)); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/EmptyEvent.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/EmptyEvent.java deleted file mode 100644 index 70c9764dd3..0000000000 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/EmptyEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.dubbo.metrics.event; - -import org.apache.dubbo.rpc.model.ApplicationModel; - -/** - * EmptyEvent, do nothing. - */ -public class EmptyEvent extends MetricsEvent { - - private static final EmptyEvent empty = new EmptyEvent(null); - - private EmptyEvent(ApplicationModel source) { - super(source, null); - } - - public static EmptyEvent instance() { - return empty; - } -} diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java index 8a1d1a8a62..bb01c88d7e 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java @@ -34,8 +34,8 @@ public class MetricsInitEvent extends TimeCounterEvent { super(source,typeWrapper); } - public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation) { - MethodMetric methodMetric = new MethodMetric(applicationModel, invocation); + public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) { + MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel); MetricsInitEvent initEvent = new MetricsInitEvent(applicationModel, METRIC_EVENT); initEvent.putAttachment(MetricsConstants.INVOCATION, invocation); initEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java index a88745ca46..ed172de6ee 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java @@ -40,10 +40,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster { @Override @SuppressWarnings({"rawtypes", "unchecked"}) public void publishEvent(MetricsEvent event) { - if (event instanceof EmptyEvent) { - return; - } - if (validateIfApplicationConfigExist(event)) return; for (MetricsListener listener : listeners) { if (listener.isSupport(event)) { @@ -75,9 +71,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster { @SuppressWarnings({"rawtypes"}) private void publishTimeEvent(MetricsEvent event, Consumer consumer) { if (validateIfApplicationConfigExist(event)) return; - if (event instanceof EmptyEvent) { - return; - } if (event instanceof TimeCounterEvent) { ((TimeCounterEvent) event).getTimePair().end(); } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java index c376fdd57d..6f4ddfffcf 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java @@ -17,12 +17,17 @@ package org.apache.dubbo.metrics.model; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.MetricsConfig; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.support.RpcUtils; import java.util.Map; import java.util.Objects; +import java.util.Optional; import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY; @@ -36,12 +41,31 @@ public class MethodMetric extends ServiceKeyMetric { private String group; private String version; - public MethodMetric(ApplicationModel applicationModel, Invocation invocation) { + + public MethodMetric(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) { super(applicationModel, MetricsSupport.getInterfaceName(invocation)); - this.methodName = RpcUtils.getMethodName(invocation); this.side = MetricsSupport.getSide(invocation); this.group = MetricsSupport.getGroup(invocation); this.version = MetricsSupport.getVersion(invocation); + this.methodName = serviceLevel ? null : RpcUtils.getMethodName(invocation); + } + + + public static boolean isServiceLevel(ApplicationModel applicationModel) { + if(applicationModel == null){ + return false; + } + ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager(); + if (applicationConfigManager == null) { + return false; + } + Optional metrics = applicationConfigManager.getMetrics(); + if (!metrics.isPresent()) { + return false; + } + String rpcLevel = metrics.map(MetricsConfig::getRpcLevel).orElse(MetricsLevel.METHOD.name()); + rpcLevel = StringUtils.isBlank(rpcLevel) ? MetricsLevel.METHOD.name() : rpcLevel; + return MetricsLevel.SERVICE.name().equalsIgnoreCase(rpcLevel); } public String getGroup() { @@ -82,13 +106,13 @@ public class MethodMetric extends ServiceKeyMetric { @Override public String toString() { return "MethodMetric{" + - "applicationName='" + getApplicationName() + '\'' + - ", side='" + side + '\'' + - ", interfaceName='" + getServiceKey() + '\'' + - ", methodName='" + methodName + '\'' + - ", group='" + group + '\'' + - ", version='" + version + '\'' + - '}'; + "applicationName='" + getApplicationName() + '\'' + + ", side='" + side + '\'' + + ", interfaceName='" + getServiceKey() + '\'' + + ", methodName='" + methodName + '\'' + + ", group='" + group + '\'' + + ", version='" + version + '\'' + + '}'; } @Override @@ -100,6 +124,7 @@ public class MethodMetric extends ServiceKeyMetric { } private volatile int hashCode = 0; + @Override public int hashCode() { if (hashCode == 0) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java index 1e3b2f4c56..ef2e173994 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java +++ b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java @@ -58,16 +58,6 @@ public class SimpleMetricsEventMulticasterTest { } - @Test - void testPublishEvent() { - - // emptyEvent do nothing - MetricsEvent emptyEvent = EmptyEvent.instance(); - eventMulticaster.publishEvent(emptyEvent); - Assertions.assertSame(obj, objects[0]); - - } - @Test void testPublishFinishEvent() { diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java index ff7abf5d3c..5cc6aec5d9 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java @@ -43,6 +43,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; @@ -56,7 +57,7 @@ import static org.apache.dubbo.metrics.model.MetricsCategory.RT; * Aggregation metrics collector implementation of {@link MetricsCollector}. * This collector only enabled when metrics aggregation config is enabled. */ -public class AggregateMetricsCollector implements MetricsCollector{ +public class AggregateMetricsCollector implements MetricsCollector { private int bucketNum = DEFAULT_BUCKET_NUM; private int timeWindowSeconds = DEFAULT_TIME_WINDOW_SECONDS; private int qpsTimeWindowMillSeconds = DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS; @@ -76,6 +77,7 @@ public class AggregateMetricsCollector implements MetricsCollector private final ConcurrentMap rtAgr = new ConcurrentHashMap<>(); + private boolean serviceLevel; public AggregateMetricsCollector(ApplicationModel applicationModel) { this.applicationModel = applicationModel; @@ -96,6 +98,7 @@ public class AggregateMetricsCollector implements MetricsCollector this.enableRt = Optional.ofNullable(aggregation.getEnableRt()).orElse(true); this.enableRequest = Optional.ofNullable(aggregation.getEnableRequest()).orElse(true); } + this.serviceLevel = MethodMetric.isServiceLevel(applicationModel); } } @@ -125,7 +128,7 @@ public class AggregateMetricsCollector implements MetricsCollector if (enableQps) { MethodMetric metric = calcWindowCounter(event, MetricsKey.METRIC_REQUESTS); TimeWindowCounter qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(qps, metric, - methodMetric -> new TimeWindowCounter(bucketNum, qpsTimeWindowMillSeconds)); + methodMetric -> new TimeWindowCounter(bucketNum, TimeUnit.MILLISECONDS.toSeconds(qpsTimeWindowMillSeconds))); qpsCounter.increment(); } } @@ -157,7 +160,7 @@ public class AggregateMetricsCollector implements MetricsCollector } private void onRTEvent(RequestEvent event) { - MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION)); + MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel); long responseTime = event.getTimePair().calc(); if (enableRt) { TimeWindowQuantile quantile = ConcurrentHashMapUtils.computeIfAbsent(rt, metric, @@ -176,7 +179,7 @@ public class AggregateMetricsCollector implements MetricsCollector private MethodMetric calcWindowCounter(RequestEvent event, MetricsKey targetKey) { MetricsPlaceValue placeType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE); MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, placeType); - MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION)); + MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel); ConcurrentMap counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>()); @@ -189,7 +192,7 @@ public class AggregateMetricsCollector implements MetricsCollector @Override public List collect() { List list = new ArrayList<>(); - if (!isCollectEnabled()){ + if (!isCollectEnabled()) { return list; } collectRequests(list); @@ -266,7 +269,7 @@ public class AggregateMetricsCollector implements MetricsCollector @Override public void initMetrics(MetricsEvent event) { - MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION)); + MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel); if (enableQps) { initMethodMetric(event); initQpsMetric(metric); @@ -279,27 +282,27 @@ public class AggregateMetricsCollector implements MetricsCollector } } - public void initMethodMetric(MetricsEvent event){ - INIT_AGG_METHOD_KEYS.stream().forEach(key->initWindowCounter(event,key)); + public void initMethodMetric(MetricsEvent event) { + INIT_AGG_METHOD_KEYS.stream().forEach(key -> initWindowCounter(event, key)); } - public void initQpsMetric(MethodMetric metric){ + public void initQpsMetric(MethodMetric metric) { ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds)); } - public void initRtMetric(MethodMetric metric){ + public void initRtMetric(MethodMetric metric) { ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds)); } - public void initRtAgrMetric(MethodMetric metric){ + public void initRtAgrMetric(MethodMetric metric) { ConcurrentHashMapUtils.computeIfAbsent(rtAgr, metric, k -> new TimeWindowAggregator(bucketNum, timeWindowSeconds)); } - public void initWindowCounter(MetricsEvent event, MetricsKey targetKey){ + public void initWindowCounter(MetricsEvent event, MetricsKey targetKey) { MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE)); - MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION)); + MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel); ConcurrentMap counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>()); diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java index 872f77df1a..932c285d8e 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java @@ -48,6 +48,8 @@ public class HistogramMetricsCollector extends AbstractMetricsListener invoker, Invocation invocation) throws RpcException { @@ -63,7 +66,7 @@ public class MetricsFilter implements ScopeModelAware { if (rpcMetricsEnable) { try { RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, appName, metricsDispatcher, - defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER); + defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER, serviceLevel); MetricsEventBus.before(requestEvent); invocation.put(METRIC_FILTER_EVENT, requestEvent); } catch (Throwable t) { diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java index 5634202384..9a53935032 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java @@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.metrics.event.MetricsEventBus; import org.apache.dubbo.metrics.event.RequestEvent; +import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.rpc.BaseFilter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -42,6 +43,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, private DefaultMetricsCollector collector; private String appName; private MetricsDispatcher metricsDispatcher; + private boolean serviceLevel; @Override public void setApplicationModel(ApplicationModel applicationModel) { @@ -49,6 +51,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class); this.appName = applicationModel.tryGetApplicationName(); this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class); + this.serviceLevel = MethodMetric.isServiceLevel(applicationModel); } @Override @@ -73,7 +76,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, if (t instanceof RpcException) { RpcException e = (RpcException) t; if (e.isForbidden()) { - MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode())); + MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode(), serviceLevel)); } } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java index 652d335ab8..ce34ce01fd 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java @@ -38,7 +38,6 @@ import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.MetricsSupport; import org.apache.dubbo.metrics.model.TimePair; import org.apache.dubbo.metrics.model.key.MetricsKey; -import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.TypeWrapper; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; @@ -90,7 +89,7 @@ class AggregateMetricsCollectorTest { public MethodMetric getTestMethodMetric() { - MethodMetric methodMetric = new MethodMetric(applicationModel, invocation); + MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel)); methodMetric.setGroup("TestGroup"); methodMetric.setVersion("1.0.0"); methodMetric.setSide("PROVIDER"); @@ -141,8 +140,8 @@ class AggregateMetricsCollectorTest { @Test void testListener() { AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel); - RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); - RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION); + RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel)); + RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel)); Assertions.assertTrue(metricsCollector.isSupport(event)); Assertions.assertTrue(metricsCollector.isSupport(beforeEvent)); @@ -200,7 +199,8 @@ class AggregateMetricsCollectorTest { when(applicationModel.getApplicationConfigManager()).thenReturn(configManager); when(applicationModel.getBeanFactory()).thenReturn(beanFactory); - when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector(applicationModel)); + DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel); + when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(defaultMetricsCollector); when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig)); when(metricsConfig.getAggregation()).thenReturn(aggregationConfig); when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE); @@ -249,7 +249,7 @@ class AggregateMetricsCollectorTest { rtList.add(30L); for (Long requestTime: rtList) { - RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); + RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel)); TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper()); testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation); testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation)); @@ -299,7 +299,7 @@ class AggregateMetricsCollectorTest { double manualP99 = requestTimes.get((int) Math.round(p99Index)); for (Long requestTime : requestTimes) { - RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); + RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel)); TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper()); testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation); testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation)); diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java index 9fd5257cc5..724c685da1 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java @@ -27,13 +27,13 @@ import org.apache.dubbo.metrics.TestMetricsInvoker; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.metrics.event.RequestEvent; import org.apache.dubbo.metrics.filter.MetricsFilter; +import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.MetricsSupport; import org.apache.dubbo.metrics.model.ServiceKeyMetric; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; -import org.apache.dubbo.metrics.model.key.TypeWrapper; import org.apache.dubbo.metrics.model.sample.CounterMetricSample; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; @@ -115,8 +115,8 @@ class DefaultCollectorTest { @Test void testListener() { DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel); - RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); - RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION); + RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel)); + RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel)); Assertions.assertTrue(metricsCollector.isSupport(event)); Assertions.assertTrue(metricsCollector.isSupport(beforeEvent)); diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java index 0db777732e..eff1d0bc8f 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java @@ -23,6 +23,7 @@ import org.apache.dubbo.config.nested.AggregationConfig; import org.apache.dubbo.metrics.aggregate.TimeWindowCounter; import org.apache.dubbo.metrics.event.MetricsEventBus; import org.apache.dubbo.metrics.event.MetricsInitEvent; +import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.ServiceKeyMetric; import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.key.MetricsLevel; @@ -96,7 +97,7 @@ class InitServiceMetricsTest { String protocolServiceKey=serviceKey+":dubbo"; RpcInvocation invocation = new RpcInvocation(serviceKey,null,methodName,interfaceName, protocolServiceKey, null, null,null,null,null,null); - MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation)); + MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation, MethodMetric.isServiceLevel(applicationModel))); } diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java index 38da8bd843..d894f15a5d 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java @@ -19,7 +19,9 @@ package org.apache.dubbo.metrics.metrics.model; import org.apache.dubbo.common.URL; import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.MetricsConfig; import org.apache.dubbo.metrics.model.MethodMetric; +import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.model.ApplicationModel; @@ -72,7 +74,7 @@ class MethodMetricTest { @Test void test() { - MethodMetric metric = new MethodMetric(applicationModel, invocation); + MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel)); Assertions.assertEquals(metric.getServiceKey(), interfaceName); Assertions.assertEquals(metric.getMethodName(), methodName); Assertions.assertEquals(metric.getGroup(), group); @@ -88,4 +90,24 @@ class MethodMetricTest { Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); } + + @Test + void testServiceMetrics() { + MetricsConfig metricConfig = new MetricsConfig(); + applicationModel.getApplicationConfigManager().setMetrics(metricConfig); + metricConfig.setRpcLevel(MetricsLevel.SERVICE.name()); + MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel)); + Assertions.assertEquals(metric.getServiceKey(), interfaceName); + Assertions.assertNull(metric.getMethodName(), methodName); + Assertions.assertEquals(metric.getGroup(), group); + Assertions.assertEquals(metric.getVersion(), version); + + Map tags = metric.getTags(); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName()); + + Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName); + Assertions.assertNull(tags.get(TAG_METHOD_KEY)); + Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); + Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); + } } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/DefaultFuture.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/DefaultFuture.java index f49ef15867..75544e9927 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/DefaultFuture.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/DefaultFuture.java @@ -276,7 +276,7 @@ public class DefaultFuture extends CompletableFuture { private String getTimeoutMessage(boolean scan) { long nowTimestamp = System.currentTimeMillis(); - return (sent > 0 ? "Waiting server-side response timeout" : "Sending request timeout in client-side") + return (sent > 0 && sent - start < timeout ? "Waiting server-side response timeout" : "Sending request timeout in client-side") + (scan ? " by scan timer" : "") + ". start time: " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(start))) + ", end time: " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(nowTimestamp))) + "," diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/DefaultFutureTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/DefaultFutureTest.java index 8188720480..171d040cd9 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/DefaultFutureTest.java +++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/DefaultFutureTest.java @@ -86,6 +86,43 @@ class DefaultFutureTest { } } + /** + * for example, it will print like this: + * before a future is created, time is : 2023-09-03 18:20:14.535 + * after a future is timeout, time is : 2023-09-03 18:20:14.669 + *

+ * The exception info print like: + * Sending request timeout in client-side by scan timer. + * start time: 2023-09-03 18:20:14.544, end time: 2023-09-03 18:20:14.598... + */ + @Test + public void clientTimeoutSend() throws Exception { + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter)); + // timeout after 5 milliseconds. + Channel channel = new MockedChannel(); + Request request = new Request(10); + DefaultFuture f = DefaultFuture.newFuture(channel, request, 5, null); + System.gc(); // events such as Full GC will increase the time required to send messages. + + // mark the future is sent + DefaultFuture.sent(channel, request); + while (!f.isDone()) { + // spin + Thread.sleep(100); + } + System.out.println("after a future is timeout , time is : " + LocalDateTime.now().format(formatter)); + + // get operate will throw a timeout exception, because the future is timeout. + try { + f.get(); + } catch (Exception e) { + Assertions.assertTrue(e.getCause() instanceof TimeoutException, "catch exception is not timeout exception!"); + System.out.println(e.getMessage()); + Assertions.assertTrue(e.getMessage().startsWith(e.getCause().getClass().getCanonicalName() + ": Sending request timeout in client-side")); + } + } + /** * for example, it will print like this: * before a future is create , time is : 2018-06-21 15:11:31 diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java index 2cadfec117..9265bad595 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java @@ -92,7 +92,7 @@ public class ExceptionFilter implements Filter, Filter.Listener { } // directly throw if it's JDK exception String className = exception.getClass().getName(); - if (className.startsWith("java.") || className.startsWith("javax.")) { + if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("jakarta.")) { return; } // directly throw if it's dubbo exception diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java index b875f4eb62..555ac3ac18 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java @@ -87,7 +87,7 @@ public abstract class AbstractInvoker implements Invoker { /** * {@link Node} destroy */ - private boolean destroyed = false; + private volatile boolean destroyed = false; /** * Whether set future to Thread Local when invocation mode is sync diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java index 8dddc8daf6..7f687a3485 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java @@ -229,6 +229,9 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis @Override public final void onCancelByRemote(TriRpcStatus status) { closed = true; + if (listener == null) { + return; + } cancellationContext.cancel(status.cause); listener.onCancel(status); } diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml index 1ed28d1b5a..c852e43863 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml +++ b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml @@ -38,9 +38,9 @@ - 1.11.3 - 1.1.4 - 1.29.0 + 1.11.4 + 1.1.5 + 1.30.1 2.16.4 0.16.0 diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml index 5155377044..ac1eca90f8 100644 --- a/dubbo-spring-boot/pom.xml +++ b/dubbo-spring-boot/pom.xml @@ -46,7 +46,7 @@ 2.20.0 - 1.14.7 + 1.14.8 diff --git a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/istio/IstioCitadelCertificateSigner.java b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/istio/IstioCitadelCertificateSigner.java index 1c8a4146db..99225b0316 100644 --- a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/istio/IstioCitadelCertificateSigner.java +++ b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/istio/IstioCitadelCertificateSigner.java @@ -175,7 +175,7 @@ public class IstioCitadelCertificateSigner implements XdsCertificateSigner { IstioCertificateServiceGrpc.IstioCertificateServiceStub stub = IstioCertificateServiceGrpc.newStub(channel); - stub = MetadataUtils.attachHeaders(stub, header); + stub = stub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(header)); CountDownLatch countDownLatch = new CountDownLatch(1); StringBuffer publicKeyBuilder = new StringBuffer();