diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml
index a33f800..d4f0d6b 100644
--- a/fizz-bootstrap/pom.xml
+++ b/fizz-bootstrap/pom.xml
@@ -12,7 +12,7 @@
com.fizzgate
fizz-bootstrap
- 2.5.2
+ 2.6
1.8
@@ -22,7 +22,7 @@
5.3.7.RELEASE
4.1.74.Final
4.4.15
- 2.17.1
+ 2.17.2
1.7.36
3.12.0
1.18.22
@@ -34,7 +34,7 @@
1.15
2.11.1
2.8.9
- 2.0.48.Final
+ 2.0.50.Final
2.2.9.RELEASE
1.7.1
1.30
diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml
index 7ef725c..6215c3b 100644
--- a/fizz-common/pom.xml
+++ b/fizz-common/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.5.2
+ 2.6
../pom.xml
4.0.0
@@ -17,6 +17,15 @@
+
+ org.springframework.cloud
+ spring-cloud-context
+
+
+ org.springframework.cloud
+ spring-cloud-commons
+
+
com.networknt
json-schema-validator-i18n-support
diff --git a/fizz-common/src/main/java/we/config/SchedConfig.java b/fizz-common/src/main/java/we/config/SchedConfig.java
index 80e0e8d..8616d93 100644
--- a/fizz-common/src/main/java/we/config/SchedConfig.java
+++ b/fizz-common/src/main/java/we/config/SchedConfig.java
@@ -25,6 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
+import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@@ -33,9 +34,10 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
*/
@ConfigurationProperties(prefix = "sched")
+@EnableScheduling
public abstract class SchedConfig implements SchedulingConfigurer {
- private int executors = 1;
+ private int executors = 2;
public void setExecutors(int es) {
executors = es;
diff --git a/fizz-common/src/main/java/we/util/StringUtils.java b/fizz-common/src/main/java/we/util/StringUtils.java
new file mode 100644
index 0000000..776ad56
--- /dev/null
+++ b/fizz-common/src/main/java/we/util/StringUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.util;
+
+import java.util.Objects;
+
+/**
+ * @author hongqiaowei
+ */
+
+public abstract class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+ private StringUtils() {
+ }
+
+ public static boolean notEquals(String s1, String s2) {
+ return !Objects.equals(s1, s2);
+ }
+}
diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml
index b79cf0c..4c1e280 100644
--- a/fizz-core/pom.xml
+++ b/fizz-core/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.5.2
+ 2.6
../pom.xml
4.0.0
diff --git a/fizz-core/src/main/java/we/beans/factory/config/FizzBeanFactoryPostProcessor.java b/fizz-core/src/main/java/we/beans/factory/config/FizzBeanFactoryPostProcessor.java
new file mode 100644
index 0000000..4f1c269
--- /dev/null
+++ b/fizz-core/src/main/java/we/beans/factory/config/FizzBeanFactoryPostProcessor.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.beans.factory.config;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.cloud.context.scope.GenericScope;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import we.config.FizzConfigConfiguration;
+import we.context.config.annotation.FizzRefreshScope;
+import we.context.event.FizzRefreshEvent;
+import we.global_resource.GlobalResource;
+import we.util.*;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware, ApplicationContextAware, Ordered {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzBeanFactoryPostProcessor.class);
+
+ private ApplicationContext applicationContext;
+
+ private ConfigurableEnvironment environment;
+
+ private final Map property2beanMap = new HashMap<>(32);
+
+ private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ String fizzConfigEnable = environment.getProperty("fizz.config.enable", Consts.S.TRUE);
+ if (fizzConfigEnable.equals(Consts.S.TRUE)) {
+ initReactiveStringRedisTemplate();
+ initFizzPropertySource();
+ initBeanProperty2beanMap(beanFactory);
+ }
+ }
+
+ private void initReactiveStringRedisTemplate() {
+ String host = environment.getProperty("aggregate.redis.host");
+ String port = environment.getProperty("aggregate.redis.port");
+ String password = environment.getProperty("aggregate.redis.password");
+ String database = environment.getProperty("aggregate.redis.database");
+ reactiveStringRedisTemplate = ReactiveRedisHelper.getStringRedisTemplate(host, Integer.parseInt(port), password, Integer.parseInt(database));
+ }
+
+ private void initFizzPropertySource() {
+ MutablePropertySources propertySources = environment.getPropertySources();
+ Map sources = new HashMap<>();
+ MapPropertySource fizzPropertySource = new MapPropertySource(FizzConfigConfiguration.PROPERTY_SOURCE, sources);
+ propertySources.addFirst(fizzPropertySource);
+
+ Result> result = Result.succ();
+ Flux> fizzConfigs = reactiveStringRedisTemplate.opsForHash().entries("fizz_config");
+ fizzConfigs.collectList()
+ .defaultIfEmpty(Collections.emptyList())
+ .flatMap(
+ es -> {
+ if (es.isEmpty()) {
+ LOGGER.info("no fizz configs");
+ } else {
+ String value = null;
+ try {
+ for (Map.Entry e : es) {
+ String key = (String) e.getKey();
+ value = (String) e.getValue();
+ Map config = JacksonUtils.readValue(value, new TypeReference>(){});
+ sources.put(key, config.get(key));
+ }
+ } catch (Throwable t) {
+ result.code = Result.FAIL;
+ result.msg = "init fizz configs error, json: " + value;
+ result.t = t;
+ }
+ }
+ return Mono.empty();
+ }
+ )
+ .onErrorReturn(
+ throwable -> {
+ result.code = Result.FAIL;
+ result.msg = "init fizz configs error";
+ result.t = throwable;
+ return true;
+ },
+ result
+ )
+ .block();
+
+ if (result.code == Result.FAIL) {
+ throw new RuntimeException(result.msg, result.t);
+ }
+ if (!sources.isEmpty()) {
+ LOGGER.info("fizz configs: {}", JacksonUtils.writeValueAsString(sources));
+ }
+
+ String channel = "fizz_config_channel";
+ reactiveStringRedisTemplate.listenToChannel(channel)
+ .doOnError(
+ t -> {
+ result.code = Result.FAIL;
+ result.msg = "lsn " + channel + " channel error";
+ result.t = t;
+ LOGGER.error("lsn channel {} error", channel, t);
+ }
+ )
+ .doOnSubscribe(
+ s -> {
+ LOGGER.info("success to lsn on {}", channel);
+ }
+ )
+ .doOnNext(
+ msg -> {
+ String message = msg.getMessage();
+ try {
+ /*Map changes = JacksonUtils.readValue(message, new TypeReference>(){});
+ boolean defaultConfigEnable = false;
+ String defaultConfigEnableStr = changes.get("fizz.default-config.enable");
+ if (defaultConfigEnableStr == null) {
+ defaultConfigEnable = environment.getProperty("fizz.default-config.enable", Boolean.class, false);
+ } else {
+ defaultConfigEnable = Boolean.parseBoolean(defaultConfigEnableStr);
+ }
+ boolean finalDefaultConfigEnable = defaultConfigEnable;
+ changes.forEach(
+ (property, value) -> {
+ if (StringUtils.isBlank(value)) {
+ if (finalDefaultConfigEnable) {
+ Object v = FizzConfigConfiguration.DEFAULT_CONFIG_MAP.get(property);
+ if (v == null) {
+ sources.remove(property);
+ } else {
+ sources.put(property, v);
+ }
+ } else {
+ sources.remove(property);
+ }
+ } else {
+ sources.put(property, value);
+ }
+ }
+ );*/
+ Map change = JacksonUtils.readValue(message, new TypeReference>(){});
+ int isDeleted = (int) change.remove("isDeleted");
+ Map.Entry propertyValue = change.entrySet().iterator().next();
+ String property = propertyValue.getKey();
+ if (isDeleted == 1) {
+ sources.remove(property);
+ } else {
+ sources.put(property, propertyValue.getValue());
+ }
+ LOGGER.info("new fizz configs: {}", JacksonUtils.writeValueAsString(sources));
+ FizzRefreshEvent refreshEvent = new FizzRefreshEvent(applicationContext, FizzRefreshEvent.ENV_CHANGE, change);
+ applicationContext.publishEvent(refreshEvent);
+ } catch (Throwable t) {
+ LOGGER.error("update fizz config {} error", message, t);
+ }
+ }
+ )
+ .subscribe();
+
+ if (result.code == Result.FAIL) {
+ throw new RuntimeException(result.msg, result.t);
+ }
+ }
+
+ private void initBeanProperty2beanMap(ConfigurableListableBeanFactory beanFactory) {
+ ClassLoader beanClassLoader = beanFactory.getBeanClassLoader();
+ Iterator beanNamesIterator = beanFactory.getBeanNamesIterator();
+ while (beanNamesIterator.hasNext()) {
+ String beanName = beanNamesIterator.next();
+ if (beanName.startsWith(GenericScope.SCOPED_TARGET_PREFIX)) {
+ AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(beanName);
+ try {
+ beanDefinition.resolveBeanClass(beanClassLoader);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ Class> beanClass = null;
+ try {
+ beanClass = beanDefinition.getBeanClass();
+ } catch (IllegalStateException e) {
+ LOGGER.warn("get {} bean class exception: {}", beanName, e.getMessage());
+ continue;
+ }
+
+ FizzRefreshScope an = beanClass.getAnnotation(FizzRefreshScope.class);
+ if (an != null) {
+ ReflectionUtils.doWithFields(
+ beanClass,
+ field -> {
+ Value annotation = field.getAnnotation(Value.class);
+ if (annotation != null) {
+ property2beanMap.put(extractPlaceholderKey(annotation.value()), beanName);
+ }
+ }
+ );
+ ReflectionUtils.doWithMethods(
+ beanClass,
+ method -> {
+ Value annotation = method.getAnnotation(Value.class);
+ if (annotation != null) {
+ property2beanMap.put(extractPlaceholderKey(annotation.value()), beanName);
+ }
+ }
+ );
+ }
+ }
+ }
+
+ LOGGER.info("fizz refresh scope property to bean map: {}", JacksonUtils.writeValueAsString(property2beanMap));
+ }
+
+ private String extractPlaceholderKey(String propertyPlaceholder) {
+ int begin = 2;
+ int end = propertyPlaceholder.indexOf(':');
+ if (end < 0) {
+ end = propertyPlaceholder.indexOf('}');
+ }
+ return propertyPlaceholder.substring(begin, end);
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.environment = (ConfigurableEnvironment) environment;
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+
+ public String getBean(String property) {
+ return property2beanMap.get(property);
+ }
+}
diff --git a/fizz-core/src/main/java/we/beans/factory/config/FizzBeanPostProcessor.java b/fizz-core/src/main/java/we/beans/factory/config/FizzBeanPostProcessor.java
new file mode 100644
index 0000000..52b3b3f
--- /dev/null
+++ b/fizz-core/src/main/java/we/beans/factory/config/FizzBeanPostProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.beans.factory.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.core.Ordered;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzBeanPostProcessor implements BeanPostProcessor, Ordered {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzBeanPostProcessor.class);
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+}
diff --git a/fizz-core/src/main/java/we/config/AggregateRedisConfigProperties.java b/fizz-core/src/main/java/we/config/AggregateRedisConfigProperties.java
index f94e51c..6d50624 100644
--- a/fizz-core/src/main/java/we/config/AggregateRedisConfigProperties.java
+++ b/fizz-core/src/main/java/we/config/AggregateRedisConfigProperties.java
@@ -21,6 +21,7 @@ import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
+import we.context.config.annotation.FizzRefreshScope;
/**
* {@link AggregateRedisConfig} properties
@@ -28,7 +29,7 @@ import org.springframework.stereotype.Component;
* @author zhongjie
*/
-@RefreshScope
+@FizzRefreshScope
@Component
@Data
public class AggregateRedisConfigProperties {
diff --git a/fizz-core/src/main/java/we/config/FizzConfigConfiguration.java b/fizz-core/src/main/java/we/config/FizzConfigConfiguration.java
new file mode 100644
index 0000000..631b9d9
--- /dev/null
+++ b/fizz-core/src/main/java/we/config/FizzConfigConfiguration.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import we.beans.factory.config.FizzBeanFactoryPostProcessor;
+import we.context.event.FizzRefreshEventListener;
+import we.context.scope.refresh.FizzRefreshScope;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author hongqiaowei
+ */
+
+@Configuration(proxyBeanMethods = false)
+public class FizzConfigConfiguration {
+
+ public static final String PROPERTY_SOURCE = "FizzPropertySource";
+
+ public static final String REFRESH_SCOPE_NAME = "FizzRefresh";
+
+ /*public static final Map DEFAULT_CONFIG_MAP = new HashMap<>();
+
+ static {
+ DEFAULT_CONFIG_MAP.put("server.port", 8600);
+ DEFAULT_CONFIG_MAP.put("gateway.prefix", "/proxy");
+ DEFAULT_CONFIG_MAP.put("server.fileUpload.maxDiskUsagePerPart", 104857600);
+ DEFAULT_CONFIG_MAP.put("cors", true);
+
+ DEFAULT_CONFIG_MAP.put("fizz.error.response.http-status.enable", true);
+ DEFAULT_CONFIG_MAP.put("fizz.error.response.code-field", "msgCode");
+ DEFAULT_CONFIG_MAP.put("fizz.error.response.message-field", "message");
+
+ DEFAULT_CONFIG_MAP.put("fizz-trace-id.header", "X-Trace-Id");
+ DEFAULT_CONFIG_MAP.put("fizz-trace-id.value-strategy", "requestId");
+ DEFAULT_CONFIG_MAP.put("fizz-trace-id.value-prefix", "fizz");
+
+ DEFAULT_CONFIG_MAP.put("custom.header.appid", "fizz-appid");
+ DEFAULT_CONFIG_MAP.put("custom.header.sign", "fizz-sign");
+ DEFAULT_CONFIG_MAP.put("custom.header.ts", "fizz-ts");
+
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.chTcpNodelay", true);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.chSoKeepAlive", true);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.chConnTimeout", 60000);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.connReadTimeout", 60000);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.connWriteTimeout", 60000);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.compress", true);
+ DEFAULT_CONFIG_MAP.put("proxy-webclient.trustInsecureSSL", true);
+
+ DEFAULT_CONFIG_MAP.put("stat.open", true);
+ DEFAULT_CONFIG_MAP.put("send-log.open", true);
+ DEFAULT_CONFIG_MAP.put("log.headers", "COOKIE,FIZZ-APPID,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV,HOST");
+
+ DEFAULT_CONFIG_MAP.put("fizz.aggregate.writeMapNullValue", false);
+ DEFAULT_CONFIG_MAP.put("gateway.aggr.proxy_set_headers", "X-Real-IP,X-Forwarded-Proto,X-Forwarded-For");
+ DEFAULT_CONFIG_MAP.put("fizz-dubbo-client.address", "zookeeper://127.0.0.1:2181");
+
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.server.enable", true);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.enable", true);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.port", 8601);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.request.timeliness", 300);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.request.timeout", 0);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.request.retry-count", 0);
+ DEFAULT_CONFIG_MAP.put("fizz.dedicated-line.client.request.retry-interval", 0);
+ }*/
+
+ @Bean
+ public FizzBeanFactoryPostProcessor fizzBeanFactoryPostProcessor() {
+ return new FizzBeanFactoryPostProcessor();
+ }
+
+ /*@Bean
+ public FizzBeanPostProcessor fizzBeanPostProcessor() {
+ return new FizzBeanPostProcessor();
+ }*/
+
+ @Bean
+ public static FizzRefreshScope fizzRefreshScope() {
+ return new FizzRefreshScope();
+ }
+
+ @Bean
+ public FizzRefreshEventListener fizzRefreshEventListener(FizzBeanFactoryPostProcessor fizzBeanFactoryPostProcessor, FizzRefreshScope scope) {
+ return new FizzRefreshEventListener(fizzBeanFactoryPostProcessor, scope);
+ }
+}
diff --git a/fizz-core/src/main/java/we/config/FizzGatewayNodeStatSchedConfig.java b/fizz-core/src/main/java/we/config/FizzGatewayNodeStatSchedConfig.java
new file mode 100644
index 0000000..8d28fa9
--- /dev/null
+++ b/fizz-core/src/main/java/we/config/FizzGatewayNodeStatSchedConfig.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import we.util.JacksonUtils;
+import we.util.NetworkUtils;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.lang.management.ManagementFactory;
+
+/**
+ * @author hongqiaowei
+ */
+
+@Configuration
+//@EnableScheduling
+public class FizzGatewayNodeStatSchedConfig extends SchedConfig {
+
+ private final static class Stat {
+ public String serviceName;
+ public String ip;
+ public int port;
+ public long ts;
+ public long startTs;
+ }
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzGatewayNodeStatSchedConfig.class);
+
+ private static final String fizz_gateway_nodes = "fizz_gateway_nodes";
+
+ @Resource
+ private ReactiveWebServerApplicationContext applicationContext;
+
+ @Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
+ private ReactiveStringRedisTemplate rt;
+
+ private Stat stat = new Stat();
+
+ private String hashKey;
+
+ @PostConstruct
+ public void postConstruct() {
+ stat.serviceName = applicationContext.getApplicationName();
+ stat.ip = NetworkUtils.getServerIp();
+ stat.port = Integer.parseInt(applicationContext.getEnvironment().getProperty("server.port", "8600"));
+ hashKey = stat.ip + ':' + stat.port;
+ stat.startTs = ManagementFactory.getRuntimeMXBean().getStartTime();
+ }
+
+ @Scheduled(cron = "${fizz-gateway-node-stat-sched.cron:*/3 * * * * ?}")
+ public void sched() {
+ stat.ts = System.currentTimeMillis();
+ String s;
+ try {
+ s = JacksonUtils.writeValueAsString(stat);
+ } catch (RuntimeException e) {
+ LOGGER.error("serial fizz gateway node stat error", e);
+ return;
+ }
+ rt.opsForHash().put(fizz_gateway_nodes, hashKey, s)
+ .doOnError(
+ t -> {
+ LOGGER.error("report fizz gateway node stat error", t);
+ }
+ )
+ .block();
+ }
+}
diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java
index 8bc2025..80c9df4 100644
--- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java
+++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java
@@ -45,7 +45,7 @@ import java.util.List;
*/
@Configuration
-@EnableScheduling
+//@EnableScheduling
public class FlowStatSchedConfig extends SchedConfig {
private static final Logger log = LoggerFactory.getLogger(FlowStatSchedConfig.class);
@@ -72,6 +72,11 @@ public class FlowStatSchedConfig extends SchedConfig {
private static final String _path = "\"path\":";
private static final String _peakRps = "\"peakRps\":";
+ private static final String _2xxStatus = "\"status2xxs\":";
+ private static final String _4xxStatus = "\"status4xxs\":";
+ private static final String _5xxStatus = "\"status5xxs\":";
+ private static final String _504Status = "\"status504s\":";
+
private static final String parentResourceList = "$prl";
@Resource
@@ -118,9 +123,12 @@ public class FlowStatSchedConfig extends SchedConfig {
int type = ResourceRateLimitConfig.Type.NODE, id = 0;
ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(resource);
- if (c == null) { // _global, service, app, app+service, ip, ip+service
+ if (c == null) { // _global, host, service, app, app+service, ip, ip+service
node = ResourceIdUtils.getNode(resource);
- if (node != null && node.equals(ResourceIdUtils.NODE)) {
+ if (node != null) {
+ if (!node.equals(ResourceIdUtils.NODE)) {
+ type = ResourceRateLimitConfig.Type.HOST;
+ }
} else {
service = ResourceIdUtils.getService(resource);
app = ResourceIdUtils.getApp(resource);
@@ -183,8 +191,8 @@ public class FlowStatSchedConfig extends SchedConfig {
b.append(_id); b.append(id); b.append(Consts.S.COMMA);
String r = null;
- if (type == ResourceRateLimitConfig.Type.NODE) {
- r = ResourceIdUtils.NODE;
+ if (type == ResourceRateLimitConfig.Type.NODE || type == ResourceRateLimitConfig.Type.HOST) {
+ r = node;
} else if (type == ResourceRateLimitConfig.Type.SERVICE_DEFAULT || type == ResourceRateLimitConfig.Type.SERVICE) {
r = service;
}
@@ -221,7 +229,13 @@ public class FlowStatSchedConfig extends SchedConfig {
b.append(_errors); b.append(w.getErrors()); b.append(Consts.S.COMMA);
b.append(_avgRespTime); b.append(w.getAvgRt()); b.append(Consts.S.COMMA);
b.append(_maxRespTime); b.append(w.getMax()); b.append(Consts.S.COMMA);
- b.append(_minRespTime); b.append(w.getMin());
+ b.append(_minRespTime); b.append(w.getMin()); b.append(Consts.S.COMMA);
+
+ b.append(_2xxStatus); b.append(w.get2xxStatus()); b.append(Consts.S.COMMA);
+ b.append(_4xxStatus); b.append(w.get4xxStatus()); b.append(Consts.S.COMMA);
+ b.append(_5xxStatus); b.append(w.get5xxStatus()); b.append(Consts.S.COMMA);
+ b.append(_504Status); b.append(w.get504Status());
+
b.append(Consts.S.RIGHT_BRACE);
String msg = b.toString();
if ("kafka".equals(flowStatSchedConfigProperties.getDest())) { // for internal use
diff --git a/fizz-core/src/main/java/we/config/SystemConfig.java b/fizz-core/src/main/java/we/config/SystemConfig.java
index eafd1ff..649542b 100644
--- a/fizz-core/src/main/java/we/config/SystemConfig.java
+++ b/fizz-core/src/main/java/we/config/SystemConfig.java
@@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
+import we.context.config.annotation.FizzRefreshScope;
import we.util.Consts;
import we.util.UUIDUtil;
import we.util.WebUtils;
@@ -37,7 +38,7 @@ import java.util.stream.Stream;
* @author hongqiaowei
*/
-@RefreshScope
+@FizzRefreshScope
@Component
public class SystemConfig {
@@ -205,51 +206,51 @@ public class SystemConfig {
appHeaders.clear();
appHeaders.add("fizz-appid");
for (String h : StringUtils.split(hdrs, ',')) {
- appHeaders.add(h.trim());
+ String trim = h.trim();
+ if (trim.equals("fizz-appid")) {
+ continue;
+ }
+ appHeaders.add(trim);
}
}
WebUtils.setAppHeaders(appHeaders);
log.info("app headers: " + appHeaders);
}
- public List getAppHeaders() {
- return appHeaders;
- }
-
@Value("${custom.header.sign:}")
public void setCustomSignHeaders(String hdrs) {
if (StringUtils.isNotBlank(hdrs)) {
signHeaders.clear();
signHeaders.add("fizz-sign");
for (String h : StringUtils.split(hdrs, ',')) {
- signHeaders.add(h.trim());
+ String trim = h.trim();
+ if (trim.equals("fizz-sign")) {
+ continue;
+ }
+ signHeaders.add(trim);
}
}
WebUtils.setSignHeaders(signHeaders);
log.info("sign headers: " + signHeaders);
}
- public List getSignHeaders() {
- return signHeaders;
- }
-
@Value("${custom.header.ts:}")
public void setCustomTimestampHeaders(String hdrs) {
if (StringUtils.isNotBlank(hdrs)) {
timestampHeaders.clear();
timestampHeaders.add("fizz-ts");
for (String h : StringUtils.split(hdrs, ',')) {
- timestampHeaders.add(h.trim());
+ String trim = h.trim();
+ if (trim.equals("fizz-ts")) {
+ continue;
+ }
+ timestampHeaders.add(trim);
}
}
WebUtils.setTimestampHeaders(timestampHeaders);
log.info("timestamp headers: " + timestampHeaders);
}
- public List getTimestampHeaders() {
- return timestampHeaders;
- }
-
@Value("${aggregate-test-auth:false}")
public void setAggregateTestAuth(boolean b) {
aggregateTestAuth = b;
@@ -303,7 +304,7 @@ public class SystemConfig {
logHeaderSet.add(fizzTraceIdHeader);
}
WebUtils.LOG_HEADER_SET = logHeaderSet;
- log.info("log header list: " + logHeaderSet.toString());
+ log.info("log headers: " + logHeaderSet.toString());
}
private void updateLogResponseBody(boolean newValue) {
diff --git a/fizz-core/src/main/java/we/context/config/annotation/FizzRefreshScope.java b/fizz-core/src/main/java/we/context/config/annotation/FizzRefreshScope.java
new file mode 100644
index 0000000..9d924c2
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/config/annotation/FizzRefreshScope.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.config.annotation;
+
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import we.config.FizzConfigConfiguration;
+
+import java.lang.annotation.*;
+
+/**
+ * @author hongqiaowei
+ */
+
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Scope(FizzConfigConfiguration.REFRESH_SCOPE_NAME)
+@Documented
+public @interface FizzRefreshScope {
+
+ ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
+}
diff --git a/fizz-core/src/main/java/we/context/event/FizzApplicationListener.java b/fizz-core/src/main/java/we/context/event/FizzApplicationListener.java
new file mode 100644
index 0000000..aa7fec9
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/event/FizzApplicationListener.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.event;
+
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.event.SmartApplicationListener;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzApplicationListener implements SmartApplicationListener {
+
+ // private static final Logger LOGGER = LoggerFactory.getLogger(FizzApplicationListener.class);
+
+ @Override
+ public boolean supportsEventType(Class extends ApplicationEvent> eventType) {
+ // return ApplicationPreparedEvent.class.isAssignableFrom(eventType);
+ return false;
+ }
+
+ @Override
+ public void onApplicationEvent(ApplicationEvent event) {
+ /*if (event instanceof ApplicationPreparedEvent) {
+ ApplicationPreparedEvent evt = (ApplicationPreparedEvent) event;
+ ConfigurableEnvironment environment = evt.getApplicationContext().getEnvironment();
+ if (environment instanceof StandardReactiveWebEnvironment) {
+ }
+ }*/
+ }
+}
diff --git a/fizz-core/src/main/java/we/context/event/FizzRefreshEvent.java b/fizz-core/src/main/java/we/context/event/FizzRefreshEvent.java
new file mode 100644
index 0000000..12c7995
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/event/FizzRefreshEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.event;
+
+import org.springframework.context.ApplicationEvent;
+import we.util.JacksonUtils;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzRefreshEvent extends ApplicationEvent {
+
+ public static final byte ENV_CHANGE = 1;
+
+ private final byte type;
+
+ private final Object data;
+
+ public FizzRefreshEvent(Object source, byte type, Object data) {
+ super(source);
+ this.type = type;
+ this.data = data;
+ }
+
+ public byte getType() {
+ return this.type;
+ }
+
+ public Object getData() {
+ return this.data;
+ }
+
+ @Override
+ public String toString() {
+ return JacksonUtils.writeValueAsString(this);
+ }
+}
diff --git a/fizz-core/src/main/java/we/context/event/FizzRefreshEventListener.java b/fizz-core/src/main/java/we/context/event/FizzRefreshEventListener.java
new file mode 100644
index 0000000..a196ab4
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/event/FizzRefreshEventListener.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.event;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.event.SmartApplicationListener;
+import we.beans.factory.config.FizzBeanFactoryPostProcessor;
+import we.context.scope.refresh.FizzRefreshScope;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzRefreshEventListener implements SmartApplicationListener {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzRefreshEventListener.class);
+
+ private final FizzBeanFactoryPostProcessor fizzBeanFactoryPostProcessor;
+
+ private final FizzRefreshScope fizzRefreshScope;
+
+ private final AtomicBoolean ready = new AtomicBoolean(false);
+
+ public FizzRefreshEventListener(FizzBeanFactoryPostProcessor fizzBeanFactoryPostProcessor, FizzRefreshScope fizzRefreshScope) {
+ this.fizzBeanFactoryPostProcessor = fizzBeanFactoryPostProcessor;
+ this.fizzRefreshScope = fizzRefreshScope;
+ }
+
+ @Override
+ public boolean supportsEventType(Class extends ApplicationEvent> eventType) {
+ return ApplicationReadyEvent.class.isAssignableFrom(eventType) || FizzRefreshEvent.class.isAssignableFrom(eventType);
+ }
+
+ @Override
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof ApplicationReadyEvent) {
+ handle((ApplicationReadyEvent) event);
+ } else if (event instanceof FizzRefreshEvent) {
+ handle((FizzRefreshEvent) event);
+ }
+ }
+
+ public void handle(ApplicationReadyEvent event) {
+ this.ready.compareAndSet(false, true);
+ }
+
+ public void handle(FizzRefreshEvent event) {
+ if (this.ready.get()) {
+ // EnvironmentChangeEvent ?
+ if (event.getType() == FizzRefreshEvent.ENV_CHANGE) {
+ /*Map> bean2propertyValuesMap = new HashMap<>();
+ Map changedPropertyValueMap = (Map) event.getData();
+ changedPropertyValueMap.forEach(
+ (property, value) -> {
+ String bean = fizzBeanFactoryPostProcessor.getBean(property);
+ if (bean != null) {
+ Map propertyValueMap = bean2propertyValuesMap.computeIfAbsent(bean, k -> new HashMap<>());
+ propertyValueMap.put(property, value);
+ }
+ }
+ );
+ bean2propertyValuesMap.forEach(
+ (bean, propertyValueMap) -> {
+ fizzRefreshScope.refresh(bean);
+ LOGGER.info("fizz refresh {} bean with {}", bean, propertyValueMap);
+ }
+ );*/
+ Map changedPropertyValue = (Map) event.getData();
+ changedPropertyValue.forEach(
+ (property, value) -> {
+ String bean = fizzBeanFactoryPostProcessor.getBean(property);
+ if (bean != null) {
+ fizzRefreshScope.refresh(bean);
+ LOGGER.info("fizz refresh {} bean with {}={}", bean, property, value);
+ }
+ }
+ );
+ }
+ }
+ }
+
+}
diff --git a/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScope.java b/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScope.java
new file mode 100644
index 0000000..323dfd5
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScope.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.scope.refresh;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.cloud.context.scope.GenericScope;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.core.Ordered;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import we.config.FizzConfigConfiguration;
+
+/**
+ * @author hongqiaowei
+ */
+
+@ManagedResource
+public class FizzRefreshScope extends GenericScope implements ApplicationContextAware,
+ ApplicationListener, Ordered {
+
+ private ApplicationContext context;
+
+ private BeanDefinitionRegistry registry;
+
+ private boolean eager = true;
+
+ private int order = Ordered.LOWEST_PRECEDENCE - 100;
+
+ public FizzRefreshScope() {
+ super.setName(FizzConfigConfiguration.REFRESH_SCOPE_NAME);
+ }
+
+ @Override
+ public int getOrder() {
+ return this.order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ public void setEager(boolean eager) {
+ this.eager = eager;
+ }
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
+ throws BeansException {
+ this.registry = registry;
+ super.postProcessBeanDefinitionRegistry(registry);
+ }
+
+ @Override
+ public void onApplicationEvent(ContextRefreshedEvent event) {
+ start(event);
+ }
+
+ public void start(ContextRefreshedEvent event) {
+ if (event.getApplicationContext() == this.context && this.eager
+ && this.registry != null) {
+ eagerlyInitialize();
+ }
+ }
+
+ private void eagerlyInitialize() {
+ for (String name : this.context.getBeanDefinitionNames()) {
+ BeanDefinition definition = this.registry.getBeanDefinition(name);
+ if (this.getName().equals(definition.getScope())
+ && !definition.isLazyInit()) {
+ Object bean = this.context.getBean(name);
+ if (bean != null) {
+ bean.getClass();
+ }
+ }
+ }
+ }
+
+ @ManagedOperation(description = "Dispose of the current instance of bean name provided and force a refresh on next method execution.")
+ public boolean refresh(String name) {
+ if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
+ name = SCOPED_TARGET_PREFIX + name;
+ }
+ if (super.destroy(name)) {
+ this.context.publishEvent(new FizzRefreshScopeRefreshedEvent(name));
+ return true;
+ }
+ return false;
+ }
+
+ @ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")
+ public void refreshAll() {
+ super.destroy();
+ this.context.publishEvent(new FizzRefreshScopeRefreshedEvent());
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) throws BeansException {
+ this.context = context;
+ }
+
+}
diff --git a/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScopeRefreshedEvent.java b/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScopeRefreshedEvent.java
new file mode 100644
index 0000000..47b0d23
--- /dev/null
+++ b/fizz-core/src/main/java/we/context/scope/refresh/FizzRefreshScopeRefreshedEvent.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.context.scope.refresh;
+
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * @author hongqiaowei
+ */
+
+public class FizzRefreshScopeRefreshedEvent extends ApplicationEvent {
+
+ public static final String DEFAULT_NAME = "__refreshAll__"; // TODO
+
+ private String name;
+
+ public FizzRefreshScopeRefreshedEvent() {
+ this(DEFAULT_NAME);
+ }
+
+ public FizzRefreshScopeRefreshedEvent(String name) {
+ super(name);
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
diff --git a/fizz-core/src/main/java/we/controller/ManagerConfigController.java b/fizz-core/src/main/java/we/controller/ManagerConfigController.java
index 5608b5e..13b9d44 100644
--- a/fizz-core/src/main/java/we/controller/ManagerConfigController.java
+++ b/fizz-core/src/main/java/we/controller/ManagerConfigController.java
@@ -17,8 +17,11 @@
package we.controller;
+import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.HttpMethod;
+import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -26,15 +29,29 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import we.controller.req.BaseManagerConfigReq;
+import we.controller.req.GetApiConfigDetailReq;
+import we.controller.req.GetApiConfigReq;
import we.controller.req.GetConfigReq;
import we.controller.req.GetConfigStrReq;
+import we.controller.resp.ApiConfigInfo;
import we.controller.resp.ConfigResp;
import we.controller.resp.ConfigStrResp;
+import we.controller.resp.GetApiConfigDetailResp;
+import we.controller.resp.GetApiConfigResp;
import we.fizz.ConfigLoader;
+import we.plugin.PluginConfig;
+import we.plugin.auth.ApiConfig;
+import we.plugin.auth.ApiConfig2appsService;
+import we.plugin.auth.ApiConfigService;
+import we.plugin.auth.GatewayGroup;
+import we.plugin.auth.GatewayGroupService;
import javax.annotation.Resource;
import javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -46,12 +63,27 @@ import java.util.stream.Collectors;
@RestController
@RequestMapping(value = "/admin/managerConfig")
public class ManagerConfigController {
+ /**
+ * 路由管理的路由类型集合
+ */
+ public static final Set API_AUTH_PROXY_MODE_SET = Sets.newHashSet(ApiConfig.Type.SERVICE_AGGREGATE,
+ ApiConfig.Type.SERVICE_DISCOVERY, ApiConfig.Type.REVERSE_PROXY, ApiConfig.Type.DUBBO);
+
@Value("${fizz.manager.config.key:fizz-manager-key}")
private String key;
@Resource
private ConfigLoader configLoader;
+ @Resource
+ private ApiConfigService apiConfigService;
+
+ @Resource
+ private GatewayGroupService gatewayGroupService;
+
+ @Resource
+ private ApiConfig2appsService apiConfig2appsService;
+
@PostMapping("/getAggregateConfigs")
public Mono getAggregateConfigs(@Valid @RequestBody GetConfigReq getConfigReq) {
this.checkSign(getConfigReq);
@@ -93,6 +125,189 @@ public class ManagerConfigController {
return Mono.just(configStrResp);
}
+ @PostMapping("/getApiConfigs")
+ public Mono getApiConfigs(@Valid @RequestBody GetApiConfigReq getApiConfigReq) {
+ this.checkSign(getApiConfigReq);
+ Integer current = getApiConfigReq.getCurrent();
+ Integer size = getApiConfigReq.getSize();
+
+ String gatewayGroup = getApiConfigReq.getGatewayGroup();
+ String service = getApiConfigReq.getService();
+ String path = getApiConfigReq.getPath();
+ Set methods = getApiConfigReq.getMethods();
+ Set plugins = getApiConfigReq.getPlugins();
+ String access = getApiConfigReq.getAccess();
+
+ Set currentGatewayGroupSet = gatewayGroupService.currentGatewayGroupSet;
+
+ List apiConfigInfoList = apiConfigService.getApiConfigMap().values().stream().filter(it -> {
+ if (!currentGatewayGroupSet.contains(it.firstGatewayGroup)) {
+ return false;
+ }
+
+ if (!API_AUTH_PROXY_MODE_SET.contains(it.type)) {
+ return false;
+ }
+
+ if (StringUtils.hasText(gatewayGroup)) {
+ if (!it.firstGatewayGroup.equals(gatewayGroup)) {
+ return false;
+ }
+ }
+
+ if (StringUtils.hasText(service)) {
+ if (!it.service.contains(service)) {
+ return false;
+ }
+ }
+
+ if (StringUtils.hasText(path)) {
+ if (!it.path.contains(path)) {
+ return false;
+ }
+ }
+
+ if (!CollectionUtils.isEmpty(methods)) {
+ if (!methods.contains(it.fizzMethod instanceof HttpMethod ? ((HttpMethod) it.fizzMethod).name() : it.fizzMethod)) {
+ return false;
+ }
+ }
+
+ if (!CollectionUtils.isEmpty(plugins)) {
+ boolean match = false;
+ for (PluginConfig pluginConfig : it.pluginConfigs) {
+ if (plugins.contains(pluginConfig.plugin)) {
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ GatewayGroup group = gatewayGroupService.get(it.firstGatewayGroup);
+ if (group != null) {
+ for (PluginConfig pluginConfig : group.pluginConfigs) {
+ if (plugins.contains(pluginConfig.plugin)) {
+ match = true;
+ break;
+ }
+ }
+ }
+
+ if (!match) {
+ return false;
+ }
+ }
+ }
+
+ if ("a".equals(access) && !it.allowAccess) {
+ return false;
+ }
+
+ if ("f".equals(access) && it.allowAccess) {
+ return false;
+ }
+
+ return true;
+ }).map(it -> {
+ ApiConfigInfo apiConfigInfo = new ApiConfigInfo();
+ apiConfigInfo.setId((long) it.id);
+ apiConfigInfo.setGatewayGroup(it.firstGatewayGroup);
+ apiConfigInfo.setProxyMode(it.type);
+ apiConfigInfo.setIsDedicatedLine(it.dedicatedLine ? (byte) 1 : 0);
+ apiConfigInfo.setService(it.service);
+ apiConfigInfo.setPath(it.path);
+ apiConfigInfo.setMethod(it.fizzMethod instanceof HttpMethod ? ((HttpMethod) it.fizzMethod).name() : "");
+
+ List gatewayGroupPluginConfigs = null;
+ GatewayGroup group = gatewayGroupService.get(it.firstGatewayGroup);
+ if (group != null) {
+ gatewayGroupPluginConfigs = group.pluginConfigs;
+ }
+ if (CollectionUtils.isEmpty(gatewayGroupPluginConfigs)) {
+ apiConfigInfo.setPlugins(it.pluginConfigs.stream().map(pluginConfig -> pluginConfig.plugin).collect(Collectors.toList()));
+ } else {
+ List pcs = new ArrayList<>(gatewayGroupPluginConfigs.size() + it.pluginConfigs.size());
+ pcs.addAll(gatewayGroupPluginConfigs);
+ pcs.addAll(it.pluginConfigs);
+ pcs.sort(null);
+ apiConfigInfo.setPlugins(pcs.stream().map(pluginConfig -> pluginConfig.plugin).collect(Collectors.toList()));
+ }
+
+ apiConfigInfo.setAccess(it.allowAccess ? "a" : "f");
+ return apiConfigInfo;
+ }).collect(Collectors.toList());
+
+ GetApiConfigResp getApiConfigResp = new GetApiConfigResp();
+ getApiConfigResp.setTotal((long) apiConfigInfoList.size());
+
+ apiConfigInfoList.sort(Comparator.comparing(ApiConfigInfo::getId).reversed());
+
+ int apiConfigListSize = apiConfigInfoList.size();
+ int startIndex = (current - 1) * size;
+ if (startIndex >= apiConfigListSize) {
+ return Mono.just(getApiConfigResp);
+ }
+
+ int endIndex = current * size;
+ if (endIndex > apiConfigListSize) {
+ endIndex = apiConfigListSize;
+ }
+ getApiConfigResp.setApiConfigInfos(apiConfigInfoList.subList(startIndex, endIndex));
+ return Mono.just(getApiConfigResp);
+ }
+
+
+ @PostMapping("/getApiConfigDetail")
+ public Mono getApiConfigDetail(@Valid @RequestBody GetApiConfigDetailReq getApiConfigDetailReq) {
+ this.checkSign(getApiConfigDetailReq);
+ Long apiConfigId = getApiConfigDetailReq.getApiConfigId();
+
+ ApiConfig apiConfig = apiConfigService.getApiConfigMap().get(apiConfigId.intValue());
+
+ GetApiConfigDetailResp getApiConfigDetailResp = new GetApiConfigDetailResp();
+ if (apiConfig == null) {
+ getApiConfigDetailResp.setExist(false);
+ } else {
+ getApiConfigDetailResp.setExist(true);
+ getApiConfigDetailResp.setId((long) apiConfig.id);
+ getApiConfigDetailResp.setGatewayGroup(apiConfig.firstGatewayGroup);
+ getApiConfigDetailResp.setService(apiConfig.service);
+ getApiConfigDetailResp.setMethod(apiConfig.fizzMethod instanceof HttpMethod ? ((HttpMethod) apiConfig.fizzMethod).name() : "");
+ getApiConfigDetailResp.setPath(apiConfig.path);
+ getApiConfigDetailResp.setAppEnabled(apiConfig.checkApp);
+ if (apiConfig.checkApp) {
+ getApiConfigDetailResp.setApps(apiConfig2appsService.getApiConfig2appsMap().get(apiConfig.id));
+ }
+ getApiConfigDetailResp.setAccess(apiConfig.allowAccess ? "a" : "f");
+ getApiConfigDetailResp.setProxyMode(apiConfig.type);
+ getApiConfigDetailResp.setBackendService(apiConfig.backendService);
+ getApiConfigDetailResp.setBackendPath(apiConfig.backendPath);
+
+ getApiConfigDetailResp.setApiPlugins(apiConfig.pluginConfigs.stream().map(pluginConfig -> {
+ GetApiConfigDetailResp.ApiPluginVO apiPluginVO = new GetApiConfigDetailResp.ApiPluginVO();
+ apiPluginVO.setPlugin(pluginConfig.plugin);
+ apiPluginVO.setConfig(pluginConfig.config);
+ apiPluginVO.setOrder(pluginConfig.order);
+ return apiPluginVO;
+ }).collect(Collectors.toList()));
+
+ getApiConfigDetailResp.setApiBackends(apiConfig.httpHostPorts);
+ getApiConfigDetailResp.setRpcMethod(apiConfig.rpcMethod);
+ getApiConfigDetailResp.setRpcParamTypes(apiConfig.rpcParamTypes);
+ getApiConfigDetailResp.setRpcVersion(apiConfig.rpcVersion);
+ getApiConfigDetailResp.setRpcGroup(apiConfig.rpcGroup);
+ getApiConfigDetailResp.setTimeout((int) apiConfig.timeout);
+ getApiConfigDetailResp.setRetryCount(apiConfig.retryCount);
+ getApiConfigDetailResp.setRetryInterval(apiConfig.retryInterval);
+
+ getApiConfigDetailResp.setIsDedicatedLine(apiConfig.dedicatedLine ? (byte) 1 : 0);
+
+ getApiConfigDetailResp.setRegistryName(apiConfig.registryCenter);
+ }
+
+ return Mono.just(getApiConfigDetailResp);
+ }
+
private void checkSign(BaseManagerConfigReq req) {
if (!req.checkSign(key)) {
throw new RuntimeException("验证签名失败");
diff --git a/fizz-core/src/main/java/we/controller/req/GetApiConfigDetailReq.java b/fizz-core/src/main/java/we/controller/req/GetApiConfigDetailReq.java
new file mode 100644
index 0000000..b78df71
--- /dev/null
+++ b/fizz-core/src/main/java/we/controller/req/GetApiConfigDetailReq.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package we.controller.req;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.util.DigestUtils;
+
+/**
+ * Get api config detail request entity
+ *
+ * @author zhongjie
+ * @since 2.6.0
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GetApiConfigDetailReq extends BaseManagerConfigReq {
+ /**
+ * Api config ID
+ */
+ private Long apiConfigId;
+
+ @Override
+ boolean innerCheckSign(String key, String sign, Long timestamp) {
+ return DigestUtils.md5DigestAsHex(String.format("%s-%s-%s", apiConfigId, timestamp, key).getBytes()).equals(sign);
+ }
+}
diff --git a/fizz-core/src/main/java/we/controller/req/GetApiConfigReq.java b/fizz-core/src/main/java/we/controller/req/GetApiConfigReq.java
new file mode 100644
index 0000000..0609433
--- /dev/null
+++ b/fizz-core/src/main/java/we/controller/req/GetApiConfigReq.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package we.controller.req;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.util.DigestUtils;
+
+import java.util.Set;
+
+/**
+ * Get api config request entity
+ *
+ * @author zhongjie
+ * @since 2.6.0
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GetApiConfigReq extends BaseManagerConfigReq {
+ /**
+ * Gateway group
+ */
+ private String gatewayGroup;
+ /**
+ * Frontend service name
+ */
+ private String service;
+ /**
+ * Frontend API path
+ */
+ private String path;
+ /**
+ * Methods
+ */
+ private Set methods;
+ /**
+ * Plugin english names
+ */
+ private Set plugins;
+ /**
+ * Can access ? a-allow,f-forbid
+ */
+ private String access;
+
+ /**
+ * Current index
+ */
+ private Integer current;
+ /**
+ * Size of page
+ */
+ private Integer size;
+
+ @Override
+ boolean innerCheckSign(String key, String sign, Long timestamp) {
+ return DigestUtils.md5DigestAsHex(String.format("%s-%s", timestamp, key).getBytes()).equals(sign);
+ }
+}
diff --git a/fizz-core/src/main/java/we/controller/resp/ApiConfigInfo.java b/fizz-core/src/main/java/we/controller/resp/ApiConfigInfo.java
new file mode 100644
index 0000000..294de37
--- /dev/null
+++ b/fizz-core/src/main/java/we/controller/resp/ApiConfigInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package we.controller.resp;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Api config entity
+ *
+ * @author zhongjie
+ * @since 2.6.0
+ */
+@Data
+public class ApiConfigInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+ /**
+ * Identifier
+ */
+ private Long id;
+ /**
+ * Gateway group
+ */
+ private String gatewayGroup;
+ /**
+ * Proxy mode: 1-aggregate 2-discovery 3-proxy 4-callback 5-Dubbo
+ */
+ private Byte proxyMode;
+ /**
+ * Is dedicated line: 0-no 1-yes
+ */
+ private Byte isDedicatedLine;
+ /**
+ * Frontend service name
+ */
+ private String service;
+ /**
+ * Frontend API path
+ */
+ private String path;
+ /**
+ * Method
+ */
+ private String method;
+ /**
+ * Can access ? a-allow,f-forbid
+ */
+ private String access;
+ /**
+ * Plugin english names
+ */
+ private List plugins;
+}
\ No newline at end of file
diff --git a/fizz-core/src/main/java/we/controller/resp/GetApiConfigDetailResp.java b/fizz-core/src/main/java/we/controller/resp/GetApiConfigDetailResp.java
new file mode 100644
index 0000000..4067430
--- /dev/null
+++ b/fizz-core/src/main/java/we/controller/resp/GetApiConfigDetailResp.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package we.controller.resp;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Get api config detail response entity
+ *
+ * @author zhongjie
+ * @since 2.6.0
+ */
+@Data
+public class GetApiConfigDetailResp implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Is exist
+ */
+ private Boolean exist;
+
+ /**
+ * ID
+ */
+ private Long id;
+ /**
+ * Gateway group
+ */
+ private String gatewayGroup;
+ /**
+ * Frontend service name
+ */
+ private String service;
+ /**
+ * Method
+ */
+ private String method;
+ /**
+ * Frontend API path
+ */
+ private String path;
+
+ /**
+ * Is app Enabled
+ */
+ private Boolean appEnabled;
+ /**
+ * App set
+ */
+ private Set apps;
+
+ /**
+ * Can access ? a-allow, f-forbid
+ */
+ private String access;
+ /**
+ * Proxy mode: 1-aggregate 2-discovery 3-proxy 4-callback 5-Dubbo
+ */
+ private Byte proxyMode;
+
+ /**
+ * Backend service name
+ */
+ private String backendService;
+ /**
+ * Backend API path
+ */
+ private String backendPath;
+
+ /**
+ * Api plugin list
+ */
+ private List apiPlugins;
+
+ /**
+ * Api backend list
+ */
+ private List apiBackends;
+ /**
+ * RPC method
+ */
+ private String rpcMethod;
+ /**
+ * RPC parameter types
+ */
+ private String rpcParamTypes;
+ /**
+ * RPC version
+ */
+ private String rpcVersion;
+ /**
+ * RPC group
+ */
+ private String rpcGroup;
+ /**
+ * Timeout millis
+ */
+ private Integer timeout;
+
+ /**
+ * Retry count
+ */
+ private Integer retryCount;
+ /**
+ * Retry interval millis
+ */
+ private Long retryInterval;
+
+ /**
+ * Is dedicated line: 0-no 1-yes
+ */
+ private Byte isDedicatedLine;
+
+ /**
+ * Registry name
+ */
+ private String registryName;
+
+ @Data
+ public static class ApiPluginVO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Plugin english name
+ */
+ public String plugin;
+ /**
+ * Config map
+ */
+ public Map config;
+ /**
+ * Order
+ */
+ public Integer order;
+ }
+}
diff --git a/fizz-core/src/main/java/we/controller/resp/GetApiConfigResp.java b/fizz-core/src/main/java/we/controller/resp/GetApiConfigResp.java
new file mode 100644
index 0000000..534d85a
--- /dev/null
+++ b/fizz-core/src/main/java/we/controller/resp/GetApiConfigResp.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package we.controller.resp;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Get api config response entity
+ *
+ * @author zhongjie
+ * @since 2.6.0
+ */
+@Data
+public class GetApiConfigResp implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Api config infos
+ */
+ private List apiConfigInfos;
+
+ /**
+ * Total count
+ */
+ private Long total;
+}
\ No newline at end of file
diff --git a/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java b/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java
index 19f4002..4cbc672 100644
--- a/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java
+++ b/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java
@@ -45,6 +45,7 @@ import we.util.ThreadContext;
import we.util.WebUtils;
import java.net.URI;
+import java.util.concurrent.TimeoutException;
/**
* @author hongqiaowei
@@ -60,6 +61,7 @@ public class FilterExceptionHandlerConfig {
@Override
public Mono handle(ServerWebExchange exchange, Throwable t) {
+ exchange.getAttributes().put(WebUtils.ORIGINAL_ERROR, t);
String traceId = WebUtils.getTraceId(exchange);
ServerHttpResponse resp = exchange.getResponse();
if (SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) {
diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java
index f12a42b..2f767e6 100644
--- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java
+++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java
@@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
@@ -32,6 +33,7 @@ import reactor.core.publisher.Mono;
import reactor.core.publisher.SignalType;
import we.config.SystemConfig;
import we.flume.clients.log4j2appender.LogService;
+import we.monitor.FizzMonitorService;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.AppService;
import we.stats.BlockType;
@@ -48,6 +50,7 @@ import we.util.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeoutException;
/**
* @author hongqiaowei
@@ -71,6 +74,10 @@ public class FlowControlFilter extends FizzWebFilter {
private static final String _fizz = "_fizz-";
+ private static final String concurrents = "concurrents";
+
+ private static final String qps = "qps";
+
@Resource
private FlowControlFilterProperties flowControlFilterProperties;
@@ -96,10 +103,14 @@ public class FlowControlFilter extends FizzWebFilter {
@Resource
private CircuitBreakManager circuitBreakManager;
+ @Resource
+ private FizzMonitorService fizzMonitorService;
+
@Override
public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) {
- String path = exchange.getRequest().getPath().value();
+ ServerHttpRequest request = exchange.getRequest();
+ String path = request.getPath().value();
int secFS = path.indexOf(Consts.S.FORWARD_SLASH, 1);
if (secFS == -1) {
return WebUtils.responseError(exchange, HttpStatus.INTERNAL_SERVER_ERROR.value(), "request path should like /optional-prefix/service-name/real-biz-path");
@@ -133,15 +144,18 @@ public class FlowControlFilter extends FizzWebFilter {
String ip = WebUtils.getOriginIp(exchange);
long currentTimeSlot = flowStat.currentTimeSlotId();
- List resourceConfigs = getFlowControlConfigs(app, ip, null, service, path);
+ String host = request.getHeaders().getFirst(HttpHeaders.HOST);
+ List resourceConfigs = getFlowControlConfigs(app, ip, host, service, path);
IncrRequestResult result = flowStat.incrRequest(exchange, resourceConfigs, currentTimeSlot, (rc, rcs) -> {
return getResourceConfigItselfAndParents(rc, rcs);
});
if (result != null && !result.isSuccess()) {
+ long currentTimeMillis = System.currentTimeMillis();
String blockedResourceId = result.getBlockedResourceId();
if (BlockType.CIRCUIT_BREAK == result.getBlockType()) {
- log.info("{} exceed {} circuit breaker limit", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
+ fizzMonitorService.sendAlarm(service, path, FizzMonitorService.CIRCUIT_BREAK_ALARM, null, currentTimeMillis);
+ log.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
String responseContentType = flowControlFilterProperties.getDegradeDefaultResponseContentType();
String responseContent = flowControlFilterProperties.getDegradeDefaultResponseContent();
@@ -171,8 +185,10 @@ public class FlowControlFilter extends FizzWebFilter {
} else {
if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) {
+ fizzMonitorService.sendAlarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, concurrents, currentTimeMillis);
log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
} else {
+ fizzMonitorService.sendAlarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, qps, currentTimeMillis);
log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
}
@@ -201,13 +217,25 @@ public class FlowControlFilter extends FizzWebFilter {
return chain.filter(exchange).doFinally(s -> {
long rt = System.currentTimeMillis() - start;
CircuitBreaker cb = exchange.getAttribute(CircuitBreaker.DETECT_REQUEST);
- if (s == SignalType.ON_ERROR || exchange.getResponse().getStatusCode().is5xxServerError()) {
- flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false);
+ HttpStatus statusCode = exchange.getResponse().getStatusCode();
+ Throwable t = exchange.getAttribute(WebUtils.ORIGINAL_ERROR);
+ if (t instanceof TimeoutException) {
+ statusCode = HttpStatus.GATEWAY_TIMEOUT;
+ }
+ if (s == SignalType.ON_ERROR || statusCode.is4xxClientError() || statusCode.is5xxServerError()) {
+ flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false, statusCode);
if (cb != null) {
cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.OPEN, currentTimeSlot, flowStat);
}
+ if (statusCode == HttpStatus.GATEWAY_TIMEOUT) {
+ fizzMonitorService.sendAlarm(finalService, finalPath, FizzMonitorService.TIMEOUT_ALARM, t.getMessage(), start);
+ } else if (statusCode.is5xxServerError()) {
+ fizzMonitorService.sendAlarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, String.valueOf(statusCode.value()), start);
+ } else if (s == SignalType.ON_ERROR && t != null) {
+ fizzMonitorService.sendAlarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, t.getMessage(), start);
+ }
} else {
- flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true);
+ flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true, statusCode);
if (cb != null) {
cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeSlot, flowStat);
}
@@ -248,6 +276,11 @@ public class FlowControlFilter extends FizzWebFilter {
for (int i = rcs.size() - 1; i > -1; i--) {
ResourceConfig r = rcs.get(i);
String id = r.getResourceId();
+ String node = ResourceIdUtils.getNode(id);
+ if (node != null && !node.equals(ResourceIdUtils.NODE)) {
+ result.add(r);
+ continue;
+ }
String app = ResourceIdUtils.getApp(id);
String ip = ResourceIdUtils.getIp(id);
String path = ResourceIdUtils.getPath(id);
@@ -286,10 +319,17 @@ public class FlowControlFilter extends FizzWebFilter {
if (log.isDebugEnabled()) {
log.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path);
}
- List resourceConfigs = new ArrayList<>(9);
+ boolean hasHost = (StringUtils.isNotBlank(node) && !node.equals(ResourceIdUtils.NODE));
+ int sz = hasHost ? 10 : 9;
+ List resourceConfigs = new ArrayList<>(sz);
StringBuilder b = ThreadContext.getStringBuilder();
checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, ResourceIdUtils.NODE, null, null, null);
+ if (hasHost) {
+ String resourceId = ResourceIdUtils.buildResourceId(app, ip, node, service, path);
+ ResourceConfig resourceConfig = new ResourceConfig(resourceId, 0, 0);
+ resourceConfigs.add(resourceConfig);
+ }
checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, null, service, null, ResourceIdUtils.SERVICE_DEFAULT);
checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, null, service, path, null);
diff --git a/fizz-core/src/main/java/we/monitor/FizzMonitorService.java b/fizz-core/src/main/java/we/monitor/FizzMonitorService.java
new file mode 100644
index 0000000..da4693b
--- /dev/null
+++ b/fizz-core/src/main/java/we/monitor/FizzMonitorService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.monitor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import org.springframework.stereotype.Service;
+import we.config.AggregateRedisConfig;
+import we.flume.clients.log4j2appender.LogService;
+import we.util.Consts;
+import we.util.ThreadContext;
+
+import javax.annotation.Resource;
+
+/**
+ * @author hongqiaowei
+ */
+
+@Service
+public class FizzMonitorService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzMonitorService.class);
+
+ public static final byte ERROR_ALARM = 1;
+ public static final byte TIMEOUT_ALARM = 2;
+ public static final byte RATE_LIMIT_ALARM = 3;
+ public static final byte CIRCUIT_BREAK_ALARM = 4;
+
+ private static final String _service = "\"service\":";
+ private static final String _path = "\"path\":";
+ private static final String _type = "\"type\":";
+ private static final String _desc = "\"desc\":";
+ private static final String _timestamp = "\"timestamp\":";
+
+ @Value("${fizz.monitor.alarm.enable:true}")
+ private boolean alarmEnable;
+
+ @Value("${fizz.monitor.alarm.dest:redis}")
+ private String dest;
+
+ @Value("${fizz.monitor.alarm.queue:fizz_alarm_channel}")
+ private String queue;
+
+ @Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
+ private ReactiveStringRedisTemplate rt;
+
+ public void sendAlarm(String service, String path, byte type, String desc, long timestamp) {
+ if (alarmEnable) {
+ StringBuilder b = ThreadContext.getStringBuilder();
+ b.append(Consts.S.LEFT_BRACE);
+ b.append(_service); toJsonStrVal(b, service); b.append(Consts.S.COMMA);
+ b.append(_path); toJsonStrVal(b, path); b.append(Consts.S.COMMA);
+ b.append(_type); b.append(type); b.append(Consts.S.COMMA);
+
+ if (desc != null) {
+ b.append(_desc); toJsonStrVal(b, desc); b.append(Consts.S.COMMA);
+ }
+
+ b.append(_timestamp) .append(timestamp);
+ b.append(Consts.S.RIGHT_BRACE);
+ String msg = b.toString();
+ if (Consts.KAFKA.equals(dest)) { // for internal use
+ LOGGER.warn(msg, LogService.HANDLE_STGY, LogService.toKF(queue));
+ } else {
+ rt.convertAndSend(queue, msg).subscribe();
+ }
+ }
+ }
+
+ private static void toJsonStrVal(StringBuilder b, String value) {
+ b.append(Consts.S.DOUBLE_QUOTE).append(value).append(Consts.S.DOUBLE_QUOTE);
+ }
+
+}
diff --git a/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java b/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java
index 50fd0ba..e785603 100644
--- a/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java
+++ b/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java
@@ -317,6 +317,10 @@ public class ApiConfigService implements ApplicationListener getApiConfigMap() {
+ return apiConfigMap;
+ }
+
/**
* @deprecated
*/
diff --git a/fizz-core/src/main/java/we/plugin/stat/StatPluginFilterProperties.java b/fizz-core/src/main/java/we/plugin/stat/StatPluginFilterProperties.java
index e09820c..cd8b471 100644
--- a/fizz-core/src/main/java/we/plugin/stat/StatPluginFilterProperties.java
+++ b/fizz-core/src/main/java/we/plugin/stat/StatPluginFilterProperties.java
@@ -21,6 +21,7 @@ import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
+import we.context.config.annotation.FizzRefreshScope;
/**
* {@link StatPluginFilter} properties
@@ -28,7 +29,7 @@ import org.springframework.stereotype.Component;
* @author zhongjie
*/
-@RefreshScope
+@FizzRefreshScope
@Component
@Data
public class StatPluginFilterProperties {
diff --git a/fizz-core/src/main/java/we/proxy/dubbo/ApacheDubboGenericServiceProperties.java b/fizz-core/src/main/java/we/proxy/dubbo/ApacheDubboGenericServiceProperties.java
index 27d413a..027b41c 100644
--- a/fizz-core/src/main/java/we/proxy/dubbo/ApacheDubboGenericServiceProperties.java
+++ b/fizz-core/src/main/java/we/proxy/dubbo/ApacheDubboGenericServiceProperties.java
@@ -20,13 +20,14 @@ import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
+import we.context.config.annotation.FizzRefreshScope;
/**
* {@link ApacheDubboGenericService} properties
*
* @author zhongjie
*/
-@RefreshScope
+@FizzRefreshScope
@Component
@Data
public class ApacheDubboGenericServiceProperties {
diff --git a/fizz-core/src/main/java/we/stats/FlowStat.java b/fizz-core/src/main/java/we/stats/FlowStat.java
index 395a3bb..1ed724c 100644
--- a/fizz-core/src/main/java/we/stats/FlowStat.java
+++ b/fizz-core/src/main/java/we/stats/FlowStat.java
@@ -33,6 +33,7 @@ import java.util.function.BiFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import we.stats.circuitbreaker.CircuitBreakManager;
import we.stats.circuitbreaker.CircuitBreaker;
@@ -293,7 +294,7 @@ public class FlowStat {
* @param rt
* @param isSuccess
*/
- public void addRequestRT(List resourceConfigs, long timeSlotId, long rt, boolean isSuccess) {
+ public void addRequestRT(List resourceConfigs, long timeSlotId, long rt, boolean isSuccess, HttpStatus statusCode) {
if (resourceConfigs == null || resourceConfigs.size() == 0) {
return;
}
@@ -301,10 +302,23 @@ public class FlowStat {
ResourceStat resourceStat = getResourceStat(resourceConfigs.get(i).getResourceId());
resourceStat.decrConcurrentRequest(timeSlotId);
resourceStat.addRequestRT(timeSlotId, rt, isSuccess);
+
+ if (statusCode.is2xxSuccessful()) {
+ resourceStat.incr2xxStatusCount(timeSlotId);
+
+ } else if (statusCode.is4xxClientError()) {
+ resourceStat.incr4xxStatusCount(timeSlotId);
+
+ } else if (statusCode.is5xxServerError()) {
+ resourceStat.incr5xxStatusCount(timeSlotId);
+
+ } else if (statusCode == HttpStatus.GATEWAY_TIMEOUT) {
+ resourceStat.incr504StatusCount(timeSlotId);
+ }
}
}
- public void addRequestRT(ServerWebExchange exchange, List resourceConfigs, long timeSlotId, long rt, boolean isSuccess) {
+ /*public void addRequestRT(ServerWebExchange exchange, List resourceConfigs, long timeSlotId, long rt, boolean isSuccess) {
if (resourceConfigs == null || resourceConfigs.size() == 0) {
return;
}
@@ -317,7 +331,7 @@ public class FlowStat {
String service = WebUtils.getClientService(exchange);
String path = WebUtils.getClientReqPath(exchange);
circuitBreakManager.correctCircuitBreakerStateAsError(exchange, timeSlotId, this, service, path);
- }
+ }*/
/**
* Increase concurrent request counter of the specified resource
diff --git a/fizz-core/src/main/java/we/stats/ResourceStat.java b/fizz-core/src/main/java/we/stats/ResourceStat.java
index 2f2834c..0c3ea81 100644
--- a/fizz-core/src/main/java/we/stats/ResourceStat.java
+++ b/fizz-core/src/main/java/we/stats/ResourceStat.java
@@ -202,6 +202,22 @@ public class ResourceStat {
getTimeSlot(timeSlot).getGradualRejectNum().decrementAndGet();
}
+ public void incr2xxStatusCount(long timeSlot) {
+ getTimeSlot(timeSlot).get2xxStatusCount().incrementAndGet();
+ }
+
+ public void incr4xxStatusCount(long timeSlot) {
+ getTimeSlot(timeSlot).get4xxStatusCount().incrementAndGet();
+ }
+
+ public void incr5xxStatusCount(long timeSlot) {
+ getTimeSlot(timeSlot).get5xxStatusCount().incrementAndGet();
+ }
+
+ public void incr504StatusCount(long timeSlot) {
+ getTimeSlot(timeSlot).get504StatusCount().incrementAndGet();
+ }
+
/**
* Add request RT to the specified time slot
*
@@ -237,6 +253,12 @@ public class ResourceStat {
long blockReqs = 0;
long totalBlockReqs = 0;
long compReqs = 0;
+
+ int _2xxStatus = 0;
+ int _4xxStatus = 0;
+ int _5xxStatus = 0;
+ int _504Status = 0;
+
for (long i = startSlotId; i < endSlotId;) {
if (timeSlots.containsKey(i)) {
TimeSlot timeSlot = timeSlots.get(i);
@@ -252,6 +274,11 @@ public class ResourceStat {
blockReqs = blockReqs + timeSlot.getBlockRequests().get();
totalBlockReqs = totalBlockReqs + timeSlot.getTotalBlockRequests().get();
compReqs = compReqs + timeSlot.getCompReqs().get();
+
+ _2xxStatus = _2xxStatus + timeSlot.get2xxStatusCount().get();
+ _4xxStatus = _4xxStatus + timeSlot.get4xxStatusCount().get();
+ _5xxStatus = _5xxStatus + timeSlot.get5xxStatusCount().get();
+ _504Status = _504Status + timeSlot.get504StatusCount().get();
}
i = i + FlowStat.INTERVAL;
}
@@ -265,6 +292,11 @@ public class ResourceStat {
tws.setCompReqs(compReqs);
tws.setPeakRps(new BigDecimal(peakRps));
+ tws.set2xxStatus(_2xxStatus);
+ tws.set4xxStatus(_4xxStatus);
+ tws.set5xxStatus(_5xxStatus);
+ tws.set504Status(_504Status);
+
if (compReqs > 0) {
tws.setAvgRt(totalRt / compReqs);
}
@@ -308,5 +340,4 @@ public class ResourceStat {
public void setConcurrentRequests(AtomicLong concurrentRequests) {
this.concurrentRequests = concurrentRequests;
}
-
}
diff --git a/fizz-core/src/main/java/we/stats/TimeSlot.java b/fizz-core/src/main/java/we/stats/TimeSlot.java
index 433bff1..2b89508 100644
--- a/fizz-core/src/main/java/we/stats/TimeSlot.java
+++ b/fizz-core/src/main/java/we/stats/TimeSlot.java
@@ -91,6 +91,30 @@ public class TimeSlot {
private AtomicLong gradualRejectNum = new AtomicLong(0);
+ private AtomicInteger _2xxStatusCount = new AtomicInteger(0);
+
+ private AtomicInteger _4xxStatusCount = new AtomicInteger(0);
+
+ private AtomicInteger _5xxStatusCount = new AtomicInteger(0);
+
+ private AtomicInteger _504StatusCount = new AtomicInteger(0);
+
+ public AtomicInteger get2xxStatusCount() {
+ return _2xxStatusCount;
+ }
+
+ public AtomicInteger get4xxStatusCount() {
+ return _4xxStatusCount;
+ }
+
+ public AtomicInteger get5xxStatusCount() {
+ return _5xxStatusCount;
+ }
+
+ public AtomicInteger get504StatusCount() {
+ return _504StatusCount;
+ }
+
public AtomicReference getCircuitBreakState() {
return circuitBreakState;
}
diff --git a/fizz-core/src/main/java/we/stats/TimeWindowStat.java b/fizz-core/src/main/java/we/stats/TimeWindowStat.java
index 50f35b7..11efe46 100644
--- a/fizz-core/src/main/java/we/stats/TimeWindowStat.java
+++ b/fizz-core/src/main/java/we/stats/TimeWindowStat.java
@@ -90,6 +90,11 @@ public class TimeWindowStat {
*/
private Long totalBlockRequests;
+ private int _2xxStatus = 0;
+ private int _4xxStatus = 0;
+ private int _5xxStatus = 0;
+ private int _504Status = 0;
+
public Long getBlockRequests() {
return blockRequests;
}
@@ -194,4 +199,35 @@ public class TimeWindowStat {
this.peakRps = peakRps;
}
+ public void set2xxStatus(int _2xxStatus) {
+ this._2xxStatus = _2xxStatus;
+ }
+
+ public void set4xxStatus(int _4xxStatus) {
+ this._4xxStatus = _4xxStatus;
+ }
+
+ public void set5xxStatus(int _5xxStatus) {
+ this._5xxStatus = _5xxStatus;
+ }
+
+ public void set504Status(int _504status) {
+ this._504Status = _504status;
+ }
+
+ public int get2xxStatus() {
+ return _2xxStatus;
+ }
+
+ public int get4xxStatus() {
+ return _4xxStatus;
+ }
+
+ public int get5xxStatus() {
+ return _5xxStatus;
+ }
+
+ public int get504Status() {
+ return _504Status;
+ }
}
diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java
index 37ab5f7..2634d0e 100644
--- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java
+++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java
@@ -39,6 +39,7 @@ public class ResourceRateLimitConfig {
static final byte APP_DEFAULT = 5;
static final byte APP = 6;
static final byte IP = 7;
+ static final byte HOST = 8;
}
public boolean isDeleted = false;
diff --git a/fizz-core/src/main/java/we/util/WebUtils.java b/fizz-core/src/main/java/we/util/WebUtils.java
index 92885cb..4f27ffe 100644
--- a/fizz-core/src/main/java/we/util/WebUtils.java
+++ b/fizz-core/src/main/java/we/util/WebUtils.java
@@ -115,6 +115,8 @@ public abstract class WebUtils {
public static final String BODY_ENCRYPT = "b-ecyt";
+ public static final String ORIGINAL_ERROR = "origerr@";
+
private WebUtils() {
}
diff --git a/fizz-core/src/test/java/we/stats/FlowStatTests.java b/fizz-core/src/test/java/we/stats/FlowStatTests.java
index 97b339e..4cd07ee 100644
--- a/fizz-core/src/test/java/we/stats/FlowStatTests.java
+++ b/fizz-core/src/test/java/we/stats/FlowStatTests.java
@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpStatus;
import we.util.JacksonUtils;
/**
@@ -178,7 +179,7 @@ public class FlowStatTests {
assertEquals("testIncrRequestResultByResourceChain_service1", result.getBlockedResourceId());
assertEquals(BlockType.CONCURRENT_REQUEST, result.getBlockType());
- stat.addRequestRT(c1.resourceConfigs, startTimeSlotId, 1, true);
+ stat.addRequestRT(c1.resourceConfigs, startTimeSlotId, 1, true, HttpStatus.OK);
result = stat.incrRequest(c1.resourceConfigs, startTimeSlotId);
assertTrue(result.isSuccess());
@@ -197,7 +198,7 @@ public class FlowStatTests {
assertEquals("testIncrRequestResultByResourceChain_service2", result.getBlockedResourceId());
assertEquals(BlockType.QPS, result.getBlockType());
- stat.addRequestRT(c2.resourceConfigs, startTimeSlotId, 1, true);
+ stat.addRequestRT(c2.resourceConfigs, startTimeSlotId, 1, true, HttpStatus.OK);
result = stat.incrRequest(c2.resourceConfigs, startTimeSlotId);
assertTrue(!result.isSuccess());
diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml
index c6c0660..5e2ec3e 100644
--- a/fizz-plugin/pom.xml
+++ b/fizz-plugin/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.5.2
+ 2.6
../pom.xml
4.0.0
diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml
index 24aaee6..8ce2fdc 100644
--- a/fizz-spring-boot-starter/pom.xml
+++ b/fizz-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.5.2
+ 2.6
../pom.xml
4.0.0
diff --git a/fizz-spring-boot-starter/src/main/resources/META-INF/spring.factories b/fizz-spring-boot-starter/src/main/resources/META-INF/spring.factories
index 2a375f2..184e664 100644
--- a/fizz-spring-boot-starter/src/main/resources/META-INF/spring.factories
+++ b/fizz-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -47,3 +47,6 @@ we.proxy.RpcInstanceServiceImpl,\
we.stats.ratelimit.ResourceRateLimitConfigService,\
we.global_resource.GlobalResourceService,\
we.dedicated_line.DedicatedLineWebServer
+
+# Application Listeners
+org.springframework.context.ApplicationListener=we.context.event.FizzApplicationListener
diff --git a/pom.xml b/pom.xml
index 549194c..5fec0b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
2.2.6.RELEASE
4.1.74.Final
4.4.15
- 2.17.1
+ 2.17.2
1.7.36
2.7.5
1.16.1
@@ -22,7 +22,7 @@
0.8.2
0.9.11
2.11.1
- 2.0.48.Final
+ 2.0.50.Final
2.2.9.RELEASE
1.7.1
1.30
@@ -38,7 +38,7 @@
fizz-gateway-community
${project.artifactId}
fizz gateway community
- 2.5.2
+ 2.6
pom
fizz-common
@@ -443,7 +443,7 @@
cn.hutool
hutool-crypto
- 5.7.21
+ 5.7.22