diff --git a/.lombok.config b/.lombok.config
new file mode 100644
index 000000000..5e75e2aa0
--- /dev/null
+++ b/.lombok.config
@@ -0,0 +1,5 @@
+# 构造器注入的时候自动复制字段上边的注解
+lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
+lombok.copyableannotations += org.springframework.beans.factory.annotation.Qualifier
+lombok.copyableannotations += org.springframework.context.annotation.Lazy
+
diff --git a/pigx-app-server/pigx-app-server-biz/pom.xml b/pigx-app-server/pigx-app-server-biz/pom.xml
index 03a9bdc9d..5ab43f966 100644
--- a/pigx-app-server/pigx-app-server-biz/pom.xml
+++ b/pigx-app-server/pigx-app-server-biz/pom.xml
@@ -72,7 +72,7 @@
com.baomidou
- mybatis-plus-boot-starter
+ mybatis-plus-spring-boot3-starter
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
index 51b56f01e..6f6e05a13 100644
--- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
@@ -35,6 +35,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
@@ -71,14 +72,14 @@ public class AuthorizationServerConfiguration {
PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
- http.apply(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
+ http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter
.accessTokenResponseHandler(successEventHandler) // 登录成功处理器
.errorResponseHandler(failureEventHandler);// 登录失败处理器
}).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证
oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
- .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)));
+ .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)),Customizer.withDefaults());
AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[] {
AntPathRequestMatcher.antMatcher("/token/**"), AntPathRequestMatcher.antMatcher("/actuator/**"),
@@ -89,10 +90,10 @@ public class AuthorizationServerConfiguration {
authorizeRequests.requestMatchers(requestMatchers).permitAll();
authorizeRequests.anyRequest().authenticated();
})
- .apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
+ .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
.authorizationServerSettings(
- AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()));
- http.apply(new FormIdentityLoginConfigurer());
+ AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), Customizer.withDefaults());
+ http.with(new FormIdentityLoginConfigurer(), Customizer.withDefaults());
DefaultSecurityFilterChain securityFilterChain = http.build();
// 注入自定义授权模式实现
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java
index 741037b38..2a63a4b92 100644
--- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java
@@ -61,7 +61,6 @@ public class PigxDaoAuthenticationProvider extends AbstractUserDetailsAuthentica
}
@Override
- @SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml
index a1a3622be..14026797a 100644
--- a/pigx-common/pigx-common-bom/pom.xml
+++ b/pigx-common/pigx-common-bom/pom.xml
@@ -18,11 +18,11 @@
5.3.0
- 3.5.4
- 1.4.6
- 4.2.0
+ 3.5.5
+ 1.4.10
+ 4.3.01.2.20
- 5.8.22
+ 5.8.238.0.3321.3.0.08.4.1.jre8
@@ -37,7 +37,7 @@
4.0.11.13.15.3.3
- 7.0.0.M1
+ 7.0.02.5.2.RELEASE1.2.832.3.0
@@ -188,12 +188,6 @@
asm${asm.version}
-
-
- io.seata
- seata-serializer-kryo
- ${seata.version}
- com.baomidou
@@ -203,7 +197,7 @@
com.baomidou
- mybatis-plus-boot-starter
+ mybatis-plus-spring-boot3-starter${mybatis-plus.version}
diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java
deleted file mode 100644
index 7014107d4..000000000
--- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.common.data.cache;
-
-import org.springframework.dao.PessimisticLockingFailureException;
-import org.springframework.data.redis.cache.CacheStatistics;
-import org.springframework.data.redis.cache.CacheStatisticsCollector;
-import org.springframework.data.redis.cache.RedisCacheWriter;
-import org.springframework.data.redis.connection.RedisConnection;
-import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
-import org.springframework.data.redis.core.types.Expiration;
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * {@link RedisCacheWriter} implementation capable of reading/writing binary data from/to
- * Redis in {@literal standalone} and {@literal cluster} environments. Works upon a given
- * {@link RedisConnectionFactory} to obtain the actual {@link RedisConnection}.
- * {@link DefaultRedisCacheWriter} can be used in
- * {@link RedisCacheWriter#lockingRedisCacheWriter(RedisConnectionFactory) locking} or
- * {@link RedisCacheWriter#nonLockingRedisCacheWriter(RedisConnectionFactory) non-locking}
- * mode. While {@literal non-locking} aims for maximum performance it may result in
- * overlapping, non atomic, command execution for operations spanning multiple Redis
- * interactions like {@code putIfAbsent}. The {@literal locking} counterpart prevents
- * command overlap by setting an explicit lock key and checking against presence of this
- * key which leads to additional requests and potential command wait times.
- *
- * @author Christoph Strobl
- * @author Mark Paluch
- * @since 2.0
- */
-class DefaultRedisCacheWriter implements RedisCacheWriter {
-
- private final RedisConnectionFactory connectionFactory;
-
- private final Duration sleepTime;
-
- /**
- * @param connectionFactory must not be {@literal null}.
- */
- DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory) {
- this(connectionFactory, Duration.ZERO);
- }
-
- /**
- * @param connectionFactory must not be {@literal null}.
- * @param sleepTime sleep time between lock request attempts. Must not be
- * {@literal null}. Use {@link Duration#ZERO} to disable locking.
- */
- private DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
-
- Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
- Assert.notNull(sleepTime, "SleepTime must not be null!");
-
- this.connectionFactory = connectionFactory;
- this.sleepTime = sleepTime;
- }
-
- @Override
- public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
-
- Assert.notNull(name, "Name must not be null!");
- Assert.notNull(key, "Key must not be null!");
- Assert.notNull(value, "Value must not be null!");
-
- execute(name, connection -> {
-
- if (shouldExpireWithin(ttl)) {
- connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
- }
- else {
- connection.set(key, value);
- }
-
- return "OK";
- });
- }
-
- @Override
- public byte[] get(String name, byte[] key) {
-
- Assert.notNull(name, "Name must not be null!");
- Assert.notNull(key, "Key must not be null!");
-
- return execute(name, connection -> connection.get(key));
- }
-
- @Override
- public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
-
- Assert.notNull(name, "Name must not be null!");
- Assert.notNull(key, "Key must not be null!");
- Assert.notNull(value, "Value must not be null!");
-
- return execute(name, connection -> {
-
- if (isLockingCacheWriter()) {
- doLock(name, connection);
- }
-
- try {
- if (Boolean.TRUE.equals(connection.setNX(key, value))) {
-
- if (shouldExpireWithin(ttl)) {
- connection.pExpire(key, ttl.toMillis());
- }
- return null;
- }
-
- return connection.get(key);
- }
- finally {
-
- if (isLockingCacheWriter()) {
- doUnlock(name, connection);
- }
- }
- });
- }
-
- /**
- * 删除,原来是删除指定的键,目前修改为既可以删除指定键的数据,也是可以删除某个前缀开始的所有数据
- * @param name
- * @param key
- */
- @Override
- public void remove(String name, byte[] key) {
-
- Assert.notNull(name, "Name must not be null!");
- Assert.notNull(key, "Key must not be null!");
-
- execute(name, connection -> {
- // 获取某个前缀所拥有的所有的键,某个前缀开头,后面肯定是*
- Set keys = connection.keys(key);
- int delNum = 0;
- Assert.notNull(keys, "keys must not be null!");
- for (byte[] keyByte : keys) {
- delNum += connection.del(keyByte);
- }
- return delNum;
- });
- }
-
- @Override
- public void clean(String name, byte[] pattern) {
-
- Assert.notNull(name, "Name must not be null!");
- Assert.notNull(pattern, "Pattern must not be null!");
-
- execute(name, connection -> {
-
- boolean wasLocked = false;
-
- try {
-
- if (isLockingCacheWriter()) {
- doLock(name, connection);
- wasLocked = true;
- }
-
- byte[][] keys = Optional.ofNullable(connection.keys(pattern))
- .orElse(Collections.emptySet())
- .toArray(new byte[0][]);
-
- if (keys.length > 0) {
- connection.del(keys);
- }
- }
- finally {
-
- if (wasLocked && isLockingCacheWriter()) {
- doUnlock(name, connection);
- }
- }
-
- return "OK";
- });
- }
-
- @Override
- public void clearStatistics(String s) {
-
- }
-
- @Override
- public RedisCacheWriter withStatisticsCollector(CacheStatisticsCollector cacheStatisticsCollector) {
- return null;
- }
-
- /**
- * Explicitly set a write lock on a cache.
- * @param name the name of the cache to lock.
- */
- void lock(String name) {
- execute(name, connection -> doLock(name, connection));
- }
-
- /**
- * Explicitly remove a write lock from a cache.
- * @param name the name of the cache to unlock.
- */
- void unlock(String name) {
- executeLockFree(connection -> doUnlock(name, connection));
- }
-
- private Boolean doLock(String name, RedisConnection connection) {
- return connection.setNX(createCacheLockKey(name), new byte[0]);
- }
-
- private Long doUnlock(String name, RedisConnection connection) {
- return connection.del(createCacheLockKey(name));
- }
-
- boolean doCheckLock(String name, RedisConnection connection) {
- return connection.exists(createCacheLockKey(name));
- }
-
- /**
- * @return {@literal true} if {@link RedisCacheWriter} uses locks.
- */
- private boolean isLockingCacheWriter() {
- return !sleepTime.isZero() && !sleepTime.isNegative();
- }
-
- private T execute(String name, Function callback) {
-
- try (RedisConnection connection = connectionFactory.getConnection()) {
- checkAndPotentiallyWaitUntilUnlocked(name, connection);
- return callback.apply(connection);
- }
- }
-
- private void executeLockFree(Consumer callback) {
- try (RedisConnection connection = connectionFactory.getConnection()) {
- callback.accept(connection);
- }
- }
-
- private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
-
- if (!isLockingCacheWriter()) {
- return;
- }
-
- try {
- while (doCheckLock(name, connection)) {
- Thread.sleep(sleepTime.toMillis());
- }
- }
- catch (InterruptedException ex) {
-
- // Re-interrupt current thread, to allow other participants to react.
- Thread.currentThread().interrupt();
-
- throw new PessimisticLockingFailureException(
- String.format("Interrupted while waiting to unlock cache %s", name), ex);
- }
- }
-
- private static boolean shouldExpireWithin(@Nullable Duration ttl) {
- return ttl != null && !ttl.isZero() && !ttl.isNegative();
- }
-
- private static byte[] createCacheLockKey(String name) {
- return (name + "~lock").getBytes(StandardCharsets.UTF_8);
- }
-
- @Override
- public CacheStatistics getCacheStatistics(String s) {
- return null;
- }
-
-}
diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java
index 17fc7716f..8c0452418 100644
--- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java
+++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisAutoCacheManager.java
@@ -48,11 +48,13 @@ public class RedisAutoCacheManager extends RedisCacheManager {
private static final int CACHE_LENGTH = 2;
- RedisAutoCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration,
- Map initialCacheConfigurations, boolean allowInFlightCacheCreation) {
- super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
+ public RedisAutoCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration,
+ boolean allowInFlightCacheCreation,
+ Map initialCacheConfigurations) {
+ super(cacheWriter, defaultCacheConfiguration, allowInFlightCacheCreation, initialCacheConfigurations);
}
+
@Override
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) {
diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java
index beb2eda4a..8bebbb3e7 100644
--- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java
+++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java
@@ -24,20 +24,21 @@ import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
-import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
-import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* 扩展redis-cache支持注解cacheName添加超时时间
@@ -45,70 +46,74 @@ import java.util.Map;
* @author L.cm
*/
@Configuration
-@AutoConfigureAfter({ RedisAutoConfiguration.class })
-@ConditionalOnBean({ RedisConnectionFactory.class })
+@AutoConfigureAfter({RedisAutoConfiguration.class})
+@ConditionalOnBean({RedisConnectionFactory.class})
@EnableConfigurationProperties(CacheProperties.class)
public class RedisCacheAutoConfiguration {
- private final CacheProperties cacheProperties;
+ private final CacheProperties cacheProperties;
- private final CacheManagerCustomizers customizerInvoker;
+ private final CacheManagerCustomizers customizerInvoker;
- @Nullable
- private final RedisCacheConfiguration redisCacheConfiguration;
+ @Nullable
+ private final RedisCacheConfiguration redisCacheConfiguration;
- RedisCacheAutoConfiguration(CacheProperties cacheProperties, CacheManagerCustomizers customizerInvoker,
- ObjectProvider redisCacheConfiguration) {
- this.cacheProperties = cacheProperties;
- this.customizerInvoker = customizerInvoker;
- this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
- }
+ RedisCacheAutoConfiguration(CacheProperties cacheProperties, CacheManagerCustomizers customizerInvoker,
+ ObjectProvider redisCacheConfiguration) {
+ this.cacheProperties = cacheProperties;
+ this.customizerInvoker = customizerInvoker;
+ this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
+ }
- @Bean
- @Primary
- public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, ResourceLoader resourceLoader) {
- DefaultRedisCacheWriter redisCacheWriter = new DefaultRedisCacheWriter(connectionFactory);
- RedisCacheConfiguration cacheConfiguration = this.determineConfiguration(resourceLoader.getClassLoader());
- List cacheNames = this.cacheProperties.getCacheNames();
- Map initialCaches = new LinkedHashMap<>();
- if (!cacheNames.isEmpty()) {
- Map cacheConfigMap = new LinkedHashMap<>(cacheNames.size());
- cacheNames.forEach(it -> cacheConfigMap.put(it, cacheConfiguration));
- initialCaches.putAll(cacheConfigMap);
- }
- RedisAutoCacheManager cacheManager = new RedisAutoCacheManager(redisCacheWriter, cacheConfiguration,
- initialCaches, true);
- cacheManager.setTransactionAware(false);
- return this.customizerInvoker.customize(cacheManager);
- }
+ @Primary
+ @Bean("cacheResolver")
+ public CacheManager redisCacheManager(ObjectProvider connectionFactoryObjectProvider) {
+ RedisConnectionFactory connectionFactory = connectionFactoryObjectProvider.getIfAvailable();
+ Objects.requireNonNull(connectionFactory, "Bean RedisConnectionFactory is null.");
+ RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
+ RedisCacheConfiguration cacheConfiguration = this.determineConfiguration();
+ List cacheNames = this.cacheProperties.getCacheNames();
+ Map initialCaches = new LinkedHashMap<>();
+ if (!cacheNames.isEmpty()) {
+ Map cacheConfigMap = new LinkedHashMap<>(cacheNames.size());
+ cacheNames.forEach(it -> cacheConfigMap.put(it, cacheConfiguration));
+ initialCaches.putAll(cacheConfigMap);
+ }
+ boolean allowInFlightCacheCreation = true;
+ boolean enableTransactions = false;
+ RedisAutoCacheManager cacheManager = new RedisAutoCacheManager(
+ redisCacheWriter, cacheConfiguration, allowInFlightCacheCreation, initialCaches
+ );
+ cacheManager.setTransactionAware(enableTransactions);
+ return this.customizerInvoker.customize(cacheManager);
+ }
- private RedisCacheConfiguration determineConfiguration(ClassLoader classLoader) {
- if (this.redisCacheConfiguration != null) {
- return this.redisCacheConfiguration;
- }
- else {
- CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
- RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
- config = config.serializeValuesWith(RedisSerializationContext.SerializationPair
- .fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
- if (redisProperties.getTimeToLive() != null) {
- config = config.entryTtl(redisProperties.getTimeToLive());
- }
+ private RedisCacheConfiguration determineConfiguration() {
+ if (this.redisCacheConfiguration != null) {
+ return this.redisCacheConfiguration;
+ } else {
+ CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
+ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
+ config = config.serializeValuesWith(RedisSerializationContext.SerializationPair
+ .fromSerializer(RedisSerializer.java()));
+ if (redisProperties.getTimeToLive() != null) {
+ config = config.entryTtl(redisProperties.getTimeToLive());
+ }
- if (redisProperties.getKeyPrefix() != null) {
- config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
- }
+ if (redisProperties.getKeyPrefix() != null) {
+ config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
+ }
- if (!redisProperties.isCacheNullValues()) {
- config = config.disableCachingNullValues();
- }
+ if (!redisProperties.isCacheNullValues()) {
+ config = config.disableCachingNullValues();
+ }
- if (!redisProperties.isUseKeyPrefix()) {
- config = config.disableKeyPrefix();
- }
+ if (!redisProperties.isUseKeyPrefix()) {
+ config = config.disableKeyPrefix();
+ }
- return config;
- }
- }
+ return config;
+ }
+ }
}
diff --git a/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java b/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
index 6b863399f..7537623d6 100644
--- a/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
+++ b/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
@@ -13,14 +13,13 @@ import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
import reactor.core.publisher.Mono;
/**
* @author lengleng
* @date 2023-07-30
*
- * 网关异常通用处理器,只作用在webflux 环境下 , 优先级低于 {@link ResponseStatusExceptionHandler} 执行
+ * 网关异常通用处理器,只作用在webflux 环境下 , 优先级低于 ReactiveNoResourceFoundHandler 执行
*/
@Slf4j
@Order(-1)
@@ -47,7 +46,7 @@ public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
- log.error("Error rquest :{} Error Spring Cloud Gateway : {}", exchange.getRequest().getPath(),
+ log.error("Error request :{} Error Spring Cloud Gateway : {}", exchange.getRequest().getPath(),
ex.getMessage());
return bufferFactory.wrap(objectMapper.writeValueAsBytes(R.failed(ex.getMessage())));
}
diff --git a/pigx-common/pigx-common-sentinel/pom.xml b/pigx-common/pigx-common-sentinel/pom.xml
index e3f5ef485..3fe5387fb 100755
--- a/pigx-common/pigx-common-sentinel/pom.xml
+++ b/pigx-common/pigx-common-sentinel/pom.xml
@@ -1,40 +1,51 @@
-
- com.pig4cloud
- pigx-common
- 5.3.0
-
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ com.pig4cloud
+ pigx-common
+ 5.3.0
+
- 4.0.0
- jar
- pigx-common-sentinel
- sentinel服务降级熔断、限流组件
-
-
- com.pig4cloud
- pigx-common-core
-
-
- com.alibaba.cloud
- spring-cloud-starter-alibaba-sentinel
-
-
-
- org.springframework.cloud
- spring-cloud-starter-openfeign
-
-
-
- io.github.openfeign
- feign-okhttp
-
-
-
- org.springframework.security
- spring-security-core
-
-
+ 4.0.0
+ jar
+ pigx-common-sentinel
+ sentinel服务降级熔断、限流组件
+
+
+ com.pig4cloud
+ pigx-common-core
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+
+ org.springframework.security
+ spring-security-core
+
+
+
+ org.springframework
+ spring-webmvc
+ true
+
+
+ org.springframework
+ spring-webflux
+ true
+
+
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/PigxSentinelAutoConfiguration.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/PigxSentinelAutoConfiguration.java
new file mode 100755
index 000000000..69218e0a1
--- /dev/null
+++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/PigxSentinelAutoConfiguration.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.sentinel;
+
+import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
+import com.pig4cloud.pigx.common.sentinel.feign.PigxSentinelFeign;
+import com.pig4cloud.pigx.common.sentinel.handle.GlobalBizExceptionHandler;
+import com.pig4cloud.pigx.common.sentinel.handle.PigxUrlBlockHandler;
+import com.pig4cloud.pigx.common.sentinel.handle.ReactiveNoResourceFoundHandler;
+import com.pig4cloud.pigx.common.sentinel.handle.WebNoResourceFoundHandler;
+import com.pig4cloud.pigx.common.sentinel.parser.PigxHeaderRequestOriginParser;
+import feign.Feign;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+/**
+ * @author lengleng
+ * @date 2020-02-12
+ *
+ * sentinel 配置
+ */
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureBefore(SentinelFeignAutoConfiguration.class)
+public class PigxSentinelAutoConfiguration {
+
+ @Bean
+ @Scope("prototype")
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(name = "spring.cloud.openfeign.sentinel.enabled")
+ public Feign.Builder feignSentinelBuilder() {
+ return PigxSentinelFeign.builder();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ /**
+ * 创建一个块异常处理器实例
+ * 如果没有定义块异常处理器,则创建一个PigxUrlBlockHandler实例
+ */
+ public BlockExceptionHandler blockExceptionHandler() {
+ return new PigxUrlBlockHandler();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ /**
+ * 创建一个请求源解析器实例
+ * 如果没有定义请求源解析器,则创建一个PigxHeaderRequestOriginParser实例
+ */
+ public RequestOriginParser requestOriginParser() {
+ return new PigxHeaderRequestOriginParser();
+ }
+
+ /**
+ * 创建一个全局业务异常处理器实例
+ * 用于处理全局的业务异常
+ */
+ public GlobalBizExceptionHandler globalBizExceptionHandler() {
+ return new GlobalBizExceptionHandler();
+ }
+
+ /**
+ * 创建一个响应式资源未找到异常处理器实例
+ * 如果存在org.springframework.web.reactive.resource.NoResourceFoundException类,则创建一个ReactiveNoResourceFoundHandler实例
+ */
+ @Bean
+ @ConditionalOnClass(name = {"org.springframework.web.reactive.resource.NoResourceFoundException"})
+ public ReactiveNoResourceFoundHandler reactiveNoResourceFoundHandler() {
+ return new ReactiveNoResourceFoundHandler();
+ }
+
+ /**
+ * 创建一个Web资源未找到异常处理器实例
+ * 如果存在org.springframework.web.servlet.resource.NoResourceFoundException类,则创建一个WebNoResourceFoundHandler实例
+ */
+ @Bean
+ @ConditionalOnClass(name = {"org.springframework.web.servlet.resource.NoResourceFoundException"})
+ public WebNoResourceFoundHandler webNoResourceFoundHandler() {
+ return new WebNoResourceFoundHandler();
+ }
+
+}
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/SentinelAutoConfiguration.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/SentinelAutoConfiguration.java
deleted file mode 100755
index f4b37c5fb..000000000
--- a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/SentinelAutoConfiguration.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.common.sentinel;
-
-import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
-import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
-import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
-import com.pig4cloud.pigx.common.sentinel.feign.PigxSentinelFeign;
-import com.pig4cloud.pigx.common.sentinel.handle.PigxUrlBlockHandler;
-import com.pig4cloud.pigx.common.sentinel.parser.PigxHeaderRequestOriginParser;
-import feign.Feign;
-import org.springframework.boot.autoconfigure.AutoConfigureBefore;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Scope;
-
-/**
- * @author lengleng
- * @date 2020-02-12
- *
- * sentinel 配置
- */
-@Configuration(proxyBeanMethods = false)
-@AutoConfigureBefore(SentinelFeignAutoConfiguration.class)
-public class SentinelAutoConfiguration {
-
- @Bean
- @Scope("prototype")
- @ConditionalOnMissingBean
- @ConditionalOnProperty(name = "spring.cloud.openfeign.sentinel.enabled")
- public Feign.Builder feignSentinelBuilder() {
- return PigxSentinelFeign.builder();
- }
-
- @Bean
- @ConditionalOnMissingBean
- public BlockExceptionHandler blockExceptionHandler() {
- return new PigxUrlBlockHandler();
- }
-
- @Bean
- @ConditionalOnMissingBean
- public RequestOriginParser requestOriginParser() {
- return new PigxHeaderRequestOriginParser();
- }
-
-}
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelFeign.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelFeign.java
index f4e06d82d..dfcfa8eb0 100644
--- a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelFeign.java
+++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelFeign.java
@@ -12,14 +12,15 @@ import org.springframework.cloud.openfeign.FeignClientFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
-
/**
- * 重写 {@link com.alibaba.cloud.sentinel.feign.SentinelFeign} 支持自动降级注入
+ * 支持自动降级注入 重写 {@link com.alibaba.cloud.sentinel.feign.SentinelFeign}
*
* @author lengleng
* @date 2020/6/9
@@ -54,14 +55,15 @@ public final class PigxSentinelFeign {
}
@Override
- public Feign build() {
+ public Feign internalBuild() {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override
public InvocationHandler create(Target target, Map dispatch) {
+
// 查找 FeignClient 上的 降级策略
FeignClient feignClient = AnnotationUtils.findAnnotation(target.type(), FeignClient.class);
- Class fallback = feignClient.fallback();
- Class fallbackFactory = feignClient.fallbackFactory();
+ Class> fallback = feignClient.fallback();
+ Class> fallbackFactory = feignClient.fallbackFactory();
String beanName = feignClient.contextId();
if (!StringUtils.hasText(beanName)) {
@@ -69,26 +71,26 @@ public final class PigxSentinelFeign {
}
Object fallbackInstance;
- FallbackFactory fallbackFactoryInstance;
- // check fallback and fallbackFactory properties
+ FallbackFactory> fallbackFactoryInstance;
if (void.class != fallback) {
fallbackInstance = getFromContext(beanName, "fallback", fallback, target.type());
return new PigxSentinelInvocationHandler(target, dispatch,
new FallbackFactory.Default(fallbackInstance));
}
+
if (void.class != fallbackFactory) {
- fallbackFactoryInstance = (FallbackFactory) getFromContext(beanName, "fallbackFactory",
+ fallbackFactoryInstance = (FallbackFactory>) getFromContext(beanName, "fallbackFactory",
fallbackFactory, FallbackFactory.class);
return new PigxSentinelInvocationHandler(target, dispatch, fallbackFactoryInstance);
}
return new PigxSentinelInvocationHandler(target, dispatch);
}
- private Object getFromContext(String name, String type, Class fallbackType, Class targetType) {
+ private Object getFromContext(String name, String type, Class> fallbackType, Class> targetType) {
Object fallbackInstance = feignClientFactory.getInstance(name, fallbackType);
if (fallbackInstance == null) {
throw new IllegalStateException(String
- .format("No %s instance of type %s found for feign client %s", type, fallbackType, name));
+ .format("No %s instance of type %s found for feign client %s", type, fallbackType, name));
}
if (!targetType.isAssignableFrom(fallbackType)) {
@@ -101,13 +103,25 @@ public final class PigxSentinelFeign {
});
super.contract(new SentinelContractHolder(contract));
- return super.build();
+ return super.internalBuild();
+ }
+
+ private Object getFieldValue(Object instance, String fieldName) {
+ Field field = ReflectionUtils.findField(instance.getClass(), fieldName);
+ field.setAccessible(true);
+ try {
+ return field.get(instance);
+ }
+ catch (IllegalAccessException e) {
+ // ignore
+ }
+ return null;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
- feignClientFactory = this.applicationContext.getBean(FeignClientFactory.class);
+ this.feignClientFactory = this.applicationContext.getBean(FeignClientFactory.class);
}
}
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/ReactiveNoResourceFoundHandler.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/ReactiveNoResourceFoundHandler.java
new file mode 100644
index 000000000..0fc19f13a
--- /dev/null
+++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/ReactiveNoResourceFoundHandler.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.sentinel.handle;
+
+import com.pig4cloud.pigx.common.core.util.R;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.reactive.resource.NoResourceFoundException;
+
+/**
+ * @author lengleng
+ * @date 2020-06-29
+ */
+@Slf4j
+@RestController
+@RestControllerAdvice
+public class ReactiveNoResourceFoundHandler {
+
+ /**
+ * 保持和低版本请求路径不存在的行为一致
+ *
+ * [Spring Boot
+ * 3.2.0] 404 Not Found behavior #38733
+ *
+ * @param exception
+ * @return R
+ */
+ @ExceptionHandler({NoResourceFoundException.class})
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public R noResourceFoundException(NoResourceFoundException exception) {
+ log.debug("请求路径 404 {}", exception.getMessage());
+ return R.failed(exception.getMessage());
+ }
+
+}
diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/WebNoResourceFoundHandler.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/WebNoResourceFoundHandler.java
new file mode 100644
index 000000000..8899e4b25
--- /dev/null
+++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/WebNoResourceFoundHandler.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.sentinel.handle;
+
+import com.pig4cloud.pigx.common.core.util.R;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
+
+/**
+ * @author lengleng
+ * @date 2020-06-29
+ */
+@Slf4j
+@RestController
+@RestControllerAdvice
+public class WebNoResourceFoundHandler {
+
+ /**
+ * 保持和低版本请求路径不存在的行为一致
+ *