Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sofa-boot-project/sofa-boot-actuator-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package com.alipay.sofa.boot.actuator.autoconfigure.health;

import com.alipay.sofa.boot.actuator.health.HealthCheckerConfig;
import jakarta.validation.constraints.Positive;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -33,6 +35,7 @@
* Created on 2020/5/18
*/
@ConfigurationProperties("sofa.boot.actuator.health")
@Validated
public class HealthProperties {

/**
Expand All @@ -54,6 +57,7 @@ public class HealthProperties {
/**
* Timeout duration of parallel health check, in milliseconds.
*/
@Positive(message = "并行健康检查超时时间必须大于 0")
private long parallelCheckTimeout = 120 * 1000;

/**
Expand Down Expand Up @@ -84,6 +88,7 @@ public class HealthProperties {
/**
* Global {@link com.alipay.sofa.boot.actuator.health.HealthChecker} health check timeout,in milliseconds.
*/
@Positive(message = "HealthChecker 全局超时时间必须大于 0")
private int globalHealthCheckerTimeout = 60 * 1000;

/**
Expand All @@ -95,6 +100,7 @@ public class HealthProperties {
/**
* Global {@link org.springframework.boot.actuate.health.HealthIndicator} health check timeout,in milliseconds.
*/
@Positive(message = "HealthIndicator 全局超时时间必须大于 0")
private int globalHealthIndicatorTimeout = 60 * 1000;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.core.NestedExceptionUtils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
Expand Down Expand Up @@ -148,6 +149,17 @@ void customHealthCheckParallelCheck() {
});
}

@Test
void invalidHealthPropertiesShouldFailFast() {
this.contextRunner
.withPropertyValues("sofa.boot.actuator.health.parallelCheckTimeout=0")
.run((context) -> {
assertThat(context).hasFailed();
assertThat(NestedExceptionUtils.getMostSpecificCause(context.getStartupFailure()).getMessage())
.contains("并行健康检查超时时间必须大于 0");
});
}

@Test
void runWhenWithIsleConfiguration() {
this.contextRunner
Expand Down
5 changes: 5 additions & 0 deletions sofa-boot-project/sofa-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
*/
package com.alipay.sofa.boot.autoconfigure.isle;

import jakarta.validation.constraints.Positive;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -28,6 +30,7 @@
* @author huzijie
*/
@ConfigurationProperties("sofa.boot.isle")
@Validated
public class SofaModuleProperties {

/**
Expand Down Expand Up @@ -78,16 +81,19 @@ public class SofaModuleProperties {
/**
* Thead pool size factor used in parallel sofa module application context refresh.
*/
@Positive(message = "模块并行刷新线程池倍率必须大于 0")
private float parallelRefreshPoolSizeFactor = 5.0f;

/**
* Timeout used in parallel sofa module application context refresh, in milliseconds.
*/
@Positive(message = "模块并行刷新超时时间必须大于 0")
private long parallelRefreshTimeout = 60;

/**
* Monitor period used in parallel sofa module application context refresh, in milliseconds.
*/
@Positive(message = "模块并行刷新检查周期必须大于 0")
private long parallelRefreshCheckPeriod = 30;

public List<String> getActiveProfiles() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 com.alipay.sofa.boot.autoconfigure.problem;

import org.springframework.http.ProblemDetail;
import org.springframework.util.StringUtils;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ExceptionMapper;
import java.util.List;
import java.util.Locale;

/**
* Base JAX-RS exception mapper for SOFA problem detail responses.
*
* @author OpenAI
Comment on lines +33 to +34
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New classes in this module typically use a real contributor name/email in Javadoc @author tags. Using OpenAI here is inconsistent with existing conventions; please replace with the actual contributor (or remove the tag).

Suggested change
*
* @author OpenAI

Copilot uses AI. Check for mistakes.
*/
public abstract class AbstractSofaProblemDetailExceptionMapper<T extends Throwable>
implements
ExceptionMapper<T> {

private final SofaProblemDetailFactory factory;

@Context
private UriInfo uriInfo;

@Context
private HttpHeaders headers;

protected AbstractSofaProblemDetailExceptionMapper(SofaProblemDetailFactory factory) {
this.factory = factory;
}

@Override
public Response toResponse(T exception) {
ProblemDetail problemDetail = factory.create(exception, resolveInstancePath(),
resolveLocale());
return Response.status(problemDetail.getStatus())
.type(MediaType.valueOf("application/problem+json"))
.entity(factory.render(problemDetail)).build();
}

private String resolveInstancePath() {
if (uriInfo == null || uriInfo.getRequestUri() == null) {
return null;
}
String path = uriInfo.getRequestUri().getPath();
if (!StringUtils.hasText(path)) {
return null;
}
return path.startsWith("/") ? path : "/" + path;
}

private Locale resolveLocale() {
if (headers == null) {
return Locale.getDefault();
}
List<Locale> acceptableLanguages = headers.getAcceptableLanguages();
return acceptableLanguages.isEmpty() ? Locale.getDefault() : acceptableLanguages.get(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 com.alipay.sofa.boot.autoconfigure.problem;

import com.alipay.sofa.rpc.boot.common.SofaBootRpcRuntimeException;

import javax.ws.rs.ext.Provider;

/**
* JAX-RS mapper for {@link SofaBootRpcRuntimeException}.
*
* @author OpenAI
*/
@Provider
Comment on lines +21 to +28
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JAX-RS providers in this codebase appear to be registered explicitly via JAXRSProviderManager.registerCustomProviderInstance(...) (see RestFilterConfiguration). Keeping @Provider here is redundant and risks double-registration if a JAX-RS runtime also performs classpath scanning. Consider removing @Provider and relying on the explicit registration mechanism.

Also, @author OpenAI is inconsistent with existing conventions in this repository; please use the actual contributor name/email (or omit the tag).

Suggested change
import javax.ws.rs.ext.Provider;
/**
* JAX-RS mapper for {@link SofaBootRpcRuntimeException}.
*
* @author OpenAI
*/
@Provider
/**
* JAX-RS mapper for {@link SofaBootRpcRuntimeException}.
*/

Copilot uses AI. Check for mistakes.
public class SofaBootRpcRuntimeExceptionProblemDetailExceptionMapper
extends
AbstractSofaProblemDetailExceptionMapper<SofaBootRpcRuntimeException> {

public SofaBootRpcRuntimeExceptionProblemDetailExceptionMapper(SofaProblemDetailFactory factory) {
super(factory);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* 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 com.alipay.sofa.boot.autoconfigure.problem;

import com.alipay.sofa.boot.autoconfigure.rpc.SofaRpcAutoConfiguration;
import com.alipay.sofa.rpc.config.JAXRSProviderManager;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.ProblemDetail;

import javax.ws.rs.ext.ExceptionMapper;

/**
* Auto-configuration for SOFABoot problem detail support.
*
* @author OpenAI
Comment on lines +38 to +39
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New classes in this module typically use a real contributor name/email in Javadoc @author tags (see other auto-configurations in this project). Using OpenAI here is inconsistent with existing conventions; please replace with the actual contributor (or remove the tag).

Suggested change
*
* @author OpenAI

Copilot uses AI. Check for mistakes.
*/
@AutoConfiguration(after = SofaRpcAutoConfiguration.class)
@ConditionalOnClass(ProblemDetail.class)
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SofaProblemDetailAutoConfiguration is only conditional on ProblemDetail, but it always creates SofaProblemDetailFactory, which has hard references to SOFA RPC exception classes. In apps that include sofa-boot-autoconfigure but do not have rpc-sofa-boot / SOFA RPC on the classpath, this can trigger NoClassDefFoundError when the factory class is loaded. Consider adding an additional @ConditionalOnClass (or splitting configs) that gates this auto-configuration on the presence of the relevant SOFA RPC exception types (e.g., SofaRpcException / SofaRpcRuntimeException / SofaBootRpcRuntimeException).

Suggested change
@ConditionalOnClass(ProblemDetail.class)
@ConditionalOnClass(name = { "org.springframework.http.ProblemDetail",
"com.alipay.sofa.rpc.core.exception.SofaRpcException",
"com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException",
"com.alipay.sofa.boot.rpc.exception.SofaBootRpcRuntimeException" })

Copilot uses AI. Check for mistakes.
@ConditionalOnProperty(prefix = "sofa.boot.problem-detail", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SofaProblemDetailProperties.class)
public class SofaProblemDetailAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public SofaProblemDetailFactory sofaProblemDetailFactory(SofaProblemDetailProperties properties,
ObjectProvider<MessageSource> messageSource,
Environment environment) {
return new SofaProblemDetailFactory(properties, messageSource.getIfAvailable(), environment);
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
static class ServletProblemDetailConfiguration {

@Bean
@ConditionalOnMissingBean
public SofaProblemDetailExceptionHandler sofaProblemDetailExceptionHandler(SofaProblemDetailFactory factory) {
return new SofaProblemDetailExceptionHandler(factory);
}
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ExceptionMapper.class, JAXRSProviderManager.class })
static class JaxrsProblemDetailConfiguration {

@Bean
@ConditionalOnMissingBean
public SofaRpcExceptionProblemDetailExceptionMapper sofaRpcExceptionProblemDetailExceptionMapper(SofaProblemDetailFactory factory) {
SofaRpcExceptionProblemDetailExceptionMapper mapper = new SofaRpcExceptionProblemDetailExceptionMapper(
factory);
JAXRSProviderManager.registerCustomProviderInstance(mapper);
return mapper;
}

@Bean
@ConditionalOnMissingBean
public SofaRpcRuntimeExceptionProblemDetailExceptionMapper sofaRpcRuntimeExceptionProblemDetailExceptionMapper(SofaProblemDetailFactory factory) {
SofaRpcRuntimeExceptionProblemDetailExceptionMapper mapper = new SofaRpcRuntimeExceptionProblemDetailExceptionMapper(
factory);
JAXRSProviderManager.registerCustomProviderInstance(mapper);
return mapper;
}

@Bean
@ConditionalOnMissingBean
public SofaBootRpcRuntimeExceptionProblemDetailExceptionMapper sofaBootRpcRuntimeExceptionProblemDetailExceptionMapper(SofaProblemDetailFactory factory) {
SofaBootRpcRuntimeExceptionProblemDetailExceptionMapper mapper = new SofaBootRpcRuntimeExceptionProblemDetailExceptionMapper(
factory);
JAXRSProviderManager.registerCustomProviderInstance(mapper);
return mapper;
}
}
}
Loading
Loading