From ed8a2075800e7b8b82c20fed6df0e5088ae7efdb Mon Sep 17 00:00:00 2001 From: Lipeng <44571204+gaosaroma@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:55:55 +0800 Subject: [PATCH] Feat: Support web gateway config in biz module (#206) * feat: support_module_web_gateway_config * feat: add koupleless logger --- koupleless-app-starter/pom.xml | 5 + .../common/log/KouplelessLogger.java | 338 ++++++++++++++++++ .../common/log/KouplelessLoggerFactory.java | 51 +++ .../sofa/koupleless/log/log4j/log-conf.xml | 44 +++ .../sofa/koupleless/log/log4j2/log-conf.xml | 53 +++ .../sofa/koupleless/log/logback/log-conf.xml | 76 ++++ .../src/main/resources/application.properties | 4 +- .../koupleless-ext-autoconfigure/.gitignore | 38 ++ .../koupleless-ext-autoconfigure/pom.xml | 71 ++++ .../koupleless/ext/autoconfigure/.gitkeep | 0 .../gateway/CompositeBizForwardsHandler.java | 77 ++++ .../autoconfigure}/web/gateway/Forward.java | 2 +- .../web/gateway/ForwardAutoConfiguration.java | 20 +- .../web/gateway/ForwardItem.java | 2 +- .../web/gateway/ForwardItemComparator.java | 2 +- .../web/gateway/ForwardItems.java | 6 +- .../web/gateway/ForwardPath.java | 2 +- .../autoconfigure}/web/gateway/Forwards.java | 4 +- .../web/gateway/GatewayProperties.java | 3 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../koupleless/ext/autoconfigure/.gitkeep | 0 .../CompositeBizForwardsHandlerTest.java | 77 ++++ .../koupleless-ext-web-gateway/pom.xml | 19 + .../gateway/CrossContextConfiguration.java | 5 + .../ext/web/gateway/ForwardController.java | 56 ++- .../gateway/ForwardsConfChangeListener.java | 3 + .../main/resources/META-INF/spring.factories | 2 +- .../ext/web/ForwardControllerTests.java | 127 +++++-- .../web/ForwardsConfChangeListenerTests.java | 6 +- .../src/test/resources/base_forwards.yaml | 6 + .../src/test/resources/biz1_forwards.yaml | 8 + .../src/test/resources/biz2_forwards.yaml | 5 + .../src/test/resources/forwards.yaml | 13 - koupleless-ext/pom.xml | 1 + 34 files changed, 1052 insertions(+), 75 deletions(-) create mode 100644 koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLogger.java create mode 100644 koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLoggerFactory.java create mode 100644 koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j/log-conf.xml create mode 100644 koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j2/log-conf.xml create mode 100644 koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/logback/log-conf.xml create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/.gitignore create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/pom.xml create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandler.java rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/Forward.java (94%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/ForwardAutoConfiguration.java (74%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/ForwardItem.java (96%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/ForwardItemComparator.java (97%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/ForwardItems.java (93%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/ForwardPath.java (93%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/Forwards.java (95%) rename koupleless-ext/{koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext => koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure}/web/gateway/GatewayProperties.java (89%) create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep create mode 100644 koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandlerTest.java create mode 100644 koupleless-ext/koupleless-ext-web-gateway/src/test/resources/base_forwards.yaml create mode 100644 koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz1_forwards.yaml create mode 100644 koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz2_forwards.yaml delete mode 100644 koupleless-ext/koupleless-ext-web-gateway/src/test/resources/forwards.yaml diff --git a/koupleless-app-starter/pom.xml b/koupleless-app-starter/pom.xml index ceab88b89..47c3eef8e 100644 --- a/koupleless-app-starter/pom.xml +++ b/koupleless-app-starter/pom.xml @@ -16,6 +16,11 @@ com.alipay.sofa.koupleless koupleless-common + + com.alipay.sofa.koupleless + koupleless-ext-autoconfigure + ${revision} + org.mockito mockito-core diff --git a/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLogger.java b/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLogger.java new file mode 100644 index 000000000..5b692596b --- /dev/null +++ b/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLogger.java @@ -0,0 +1,338 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.common.log; + +import org.slf4j.Logger; +import org.slf4j.Marker; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: KouplelessLogger.java, v 0.1 2024年11月08日 17:30 立蓬 Exp $ + */ +public class KouplelessLogger implements Logger { + + private final Logger logger; + + public KouplelessLogger(Logger logger) { + this.logger = logger; + } + + @Override + public String getName() { + return logger.getName(); + } + + @Override + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + @Override + public void trace(String msg) { + logger.trace(msg); + } + + @Override + public void trace(String format, Object arg) { + logger.trace(format, arg); + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + logger.trace(format, arg1, arg2); + } + + @Override + public void trace(String format, Object... arguments) { + logger.trace(format, arguments); + } + + @Override + public void trace(String msg, Throwable t) { + logger.trace(msg, t); + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return logger.isTraceEnabled(); + } + + @Override + public void trace(Marker marker, String msg) { + logger.trace(marker, msg); + } + + @Override + public void trace(Marker marker, String format, Object arg) { + logger.trace(marker, format, arg); + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + logger.trace(marker, format, arg1, arg2); + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + logger.trace(marker, format, argArray); + } + + @Override + public void trace(Marker marker, String msg, Throwable t) { + logger.trace(marker, msg, t); + } + + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(String msg) { + logger.debug(msg); + } + + @Override + public void debug(String format, Object arg) { + logger.debug(format, arg); + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + logger.debug(format, arg1, arg2); + } + + @Override + public void debug(String format, Object... arguments) { + logger.debug(format, arguments); + } + + @Override + public void debug(String msg, Throwable t) { + logger.debug(msg, t); + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return logger.isDebugEnabled(marker); + } + + @Override + public void debug(Marker marker, String msg) { + logger.debug(marker, msg); + } + + @Override + public void debug(Marker marker, String format, Object arg) { + logger.debug(marker, format, arg); + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + logger.debug(marker, format, arg1, arg2); + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + logger.debug(marker, format, arguments); + } + + @Override + public void debug(Marker marker, String msg, Throwable t) { + logger.debug(marker, msg, t); + } + + @Override + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + @Override + public void info(String msg) { + logger.info(msg); + } + + @Override + public void info(String format, Object arg) { + logger.info(format, arg); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + logger.info(format, arg1, arg2); + } + + @Override + public void info(String format, Object... arguments) { + logger.info(format, arguments); + } + + @Override + public void info(String msg, Throwable t) { + logger.info(msg, t); + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return logger.isInfoEnabled(); + } + + @Override + public void info(Marker marker, String msg) { + logger.info(marker, msg); + } + + @Override + public void info(Marker marker, String format, Object arg) { + logger.info(marker, format, arg); + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + logger.info(marker, format, arg1, arg2); + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + logger.info(marker, format, arguments); + } + + @Override + public void info(Marker marker, String msg, Throwable t) { + logger.info(marker, msg, t); + } + + @Override + public boolean isWarnEnabled() { + return logger.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + logger.warn(msg); + } + + @Override + public void warn(String format, Object arg) { + logger.warn(format, arg); + } + + @Override + public void warn(String format, Object... arguments) { + logger.warn(format, arguments); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + logger.warn(format, arg1, arg2); + } + + @Override + public void warn(String msg, Throwable t) { + logger.warn(msg, t); + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return logger.isWarnEnabled(marker); + } + + @Override + public void warn(Marker marker, String msg) { + logger.warn(marker, msg); + } + + @Override + public void warn(Marker marker, String format, Object arg) { + logger.warn(marker, format, arg); + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + logger.warn(marker, format, arg1, arg2); + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + logger.warn(marker, format, arguments); + } + + @Override + public void warn(Marker marker, String msg, Throwable t) { + logger.warn(marker, msg, t); + } + + @Override + public boolean isErrorEnabled() { + return logger.isErrorEnabled(); + } + + @Override + public void error(String msg) { + logger.error(msg); + } + + @Override + public void error(String format, Object arg) { + logger.error(format, arg); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + logger.error(format, arg1, arg2); + } + + @Override + public void error(String format, Object... arguments) { + logger.error(format, arguments); + } + + @Override + public void error(String msg, Throwable t) { + logger.error(msg, t); + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return logger.isErrorEnabled(marker); + } + + @Override + public void error(Marker marker, String msg) { + logger.error(marker, msg); + } + + @Override + public void error(Marker marker, String format, Object arg) { + logger.error(marker, format, arg); + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + logger.error(marker, format, arg1, arg2); + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + logger.error(marker, format, arguments); + } + + @Override + public void error(Marker marker, String msg, Throwable t) { + logger.error(marker, msg, t); + } +} \ No newline at end of file diff --git a/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLoggerFactory.java b/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLoggerFactory.java new file mode 100644 index 000000000..be3a7d199 --- /dev/null +++ b/koupleless-common/src/main/java/com/alipay/sofa/koupleless/common/log/KouplelessLoggerFactory.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.common.log; + +import com.alipay.sofa.common.log.LoggerSpaceManager; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: KouplelessLoggerFactory.java, v 0.1 2024年11月08日 17:31 立蓬 Exp $ + */ +public class KouplelessLoggerFactory { + public static final String SOFA_KOUPLELESS_LOGGER_SPACE = "com.alipay.sofa.koupleless"; + + private static final String SOFA_KOUPLELESS_DEFAULT_LOGGER_NAME = "com.alipay.sofa.koupleless"; + + public static KouplelessLogger defaultLogger = getLogger( + SOFA_KOUPLELESS_DEFAULT_LOGGER_NAME); + + public static KouplelessLogger getLogger(Class clazz) { + if (clazz == null) { + return null; + } + return getLogger(clazz.getCanonicalName()); + } + + public static KouplelessLogger getLogger(String name) { + if (name == null || name.isEmpty()) { + return null; + } + return new KouplelessLogger( + LoggerSpaceManager.getLoggerBySpace(name, SOFA_KOUPLELESS_LOGGER_SPACE)); + } + + public static KouplelessLogger getDefaultLogger() { + return defaultLogger; + } +} \ No newline at end of file diff --git a/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j/log-conf.xml b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j/log-conf.xml new file mode 100644 index 000000000..0ba702133 --- /dev/null +++ b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j/log-conf.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j2/log-conf.xml b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j2/log-conf.xml new file mode 100644 index 000000000..767d1575f --- /dev/null +++ b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/log4j2/log-conf.xml @@ -0,0 +1,53 @@ + + + + ${sys:logging.level.com.alipay.sofa} + ${sys:logging.path} + ${sys:file.encoding} + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + + + + + + + + + + + diff --git a/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/logback/log-conf.xml b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/logback/log-conf.xml new file mode 100644 index 000000000..8f5abd7e7 --- /dev/null +++ b/koupleless-common/src/main/resources/com/alipay/sofa/koupleless/log/logback/log-conf.xml @@ -0,0 +1,76 @@ + + + + + + + + true + + error + ACCEPT + DENY + + ${logging.path}/sofa-koupleless/common-error.log + + ${logging.path}/sofa-koupleless/common-error.log.%d{yyyy-MM-dd} + 30 + + + %d %-5p %-32t - %m%n + ${file.encoding} + + + + + true + + ${logging.level.com.alipay.sofa} + ACCEPT + DENY + + ${logging.path}/sofa-koupleless/common-default.log + + ${logging.path}/sofa-koupleless/common-default.log.%d{yyyy-MM-dd} + 30 + + + %d %-5p %-32t - %m%n + ${file.encoding} + + + + + + ${LOG_PATTERN} + utf8 + + + + + + + + + + + + + + + diff --git a/koupleless-ext/archetype/koupleless-common-module-archetype/src/main/resources/archetype-resources/src/main/resources/application.properties b/koupleless-ext/archetype/koupleless-common-module-archetype/src/main/resources/archetype-resources/src/main/resources/application.properties index 7ff0abb74..2807ee03a 100644 --- a/koupleless-ext/archetype/koupleless-common-module-archetype/src/main/resources/archetype-resources/src/main/resources/application.properties +++ b/koupleless-ext/archetype/koupleless-common-module-archetype/src/main/resources/archetype-resources/src/main/resources/application.properties @@ -4,8 +4,8 @@ spring.application.name=biz1 logging.file.path=./logging/log4j2/logs/ logging.path=./logging/log4j2/logs/ -logging.level.com.alipay.sofa=DEBUG +logging.level.com.alipay.sofa=INFO logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO -logging.level.net.sf.ehcache=DEBUG +logging.level.net.sf.ehcache=INFO logging.config=classpath:log4j2-spring.xml \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-autoconfigure/.gitignore b/koupleless-ext/koupleless-ext-autoconfigure/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/koupleless-ext/koupleless-ext-autoconfigure/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-autoconfigure/pom.xml b/koupleless-ext/koupleless-ext-autoconfigure/pom.xml new file mode 100644 index 000000000..673dec170 --- /dev/null +++ b/koupleless-ext/koupleless-ext-autoconfigure/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + koupleless-ext + com.alipay.sofa.koupleless + ${revision} + ../pom.xml + + + + koupleless-ext-autoconfigure + + + + org.projectlombok + lombok + provided + + + + org.springframework.boot + spring-boot-configuration-processor + provided + + + + org.springframework.boot + spring-boot-starter + provided + + + + org.springframework + spring-context + provided + + + + com.alipay.sofa + sofa-ark-spi + + + + com.alipay.sofa + sofa-ark-api + + + + com.alipay.sofa.koupleless + koupleless-common + provided + + + + + org.mockito + mockito-inline + test + + + junit + junit + test + + + + + \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandler.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandler.java new file mode 100644 index 000000000..a15dbb489 --- /dev/null +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandler.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; + +import com.alipay.sofa.ark.spi.event.AbstractArkEvent; +import com.alipay.sofa.ark.spi.event.biz.AfterBizStartupEvent; +import com.alipay.sofa.ark.spi.event.biz.BeforeBizStopEvent; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.ark.spi.service.event.EventHandler; +import com.alipay.sofa.koupleless.common.util.ArkUtils; +import com.alipay.sofa.koupleless.common.util.SpringUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: CompositeForwards.java, v 0.1 2024年11月08日 16:00 立蓬 Exp $ + */ +public class CompositeBizForwardsHandler implements EventHandler { + private static final Map forwardsMap = new ConcurrentHashMap<>(); + + @Override + public void handleEvent(AbstractArkEvent event) { + if (ArkUtils.isMasterBiz()) { + return; + } + + // Only handle biz events. + Object obj = event.getSource(); + if (obj instanceof Biz) { + Biz biz = (Biz) obj; + handleBizEvent(event, biz); + } + } + + private void handleBizEvent(AbstractArkEvent event, Biz biz) { + // After the module is successfully installed, bean forwards will be automatically registered in the map. + if (event instanceof AfterBizStartupEvent) { + Object forwards = SpringUtils.getBean(biz, "forwards"); + + if (forwards instanceof Forwards) { + forwardsMap.put(biz.getBizClassLoader(), (Forwards) forwards); + } + } + + // Before the module uninstall, bean forwards will be automatically removed from this map. + if (event instanceof BeforeBizStopEvent) { + forwardsMap.remove(biz.getBizClassLoader()); + } + } + + @Override + public int getPriority() { + return 0; + } + + public static Map getBizForwards() { + return Collections.unmodifiableMap(forwardsMap); + } +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forward.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forward.java similarity index 94% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forward.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forward.java index 54a7131f9..4e50f20bc 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forward.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forward.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import lombok.Data; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardAutoConfiguration.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardAutoConfiguration.java similarity index 74% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardAutoConfiguration.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardAutoConfiguration.java index ac51f7d96..3ff616906 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardAutoConfiguration.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardAutoConfiguration.java @@ -14,12 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; +import com.alipay.sofa.ark.api.ArkClient; +import com.alipay.sofa.koupleless.common.util.ArkUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; /** *

ForwardAutoConfiguration class.

@@ -27,16 +31,24 @@ * @author zzl_i * @version 1.0.0 */ + +@Configuration @EnableConfigurationProperties(GatewayProperties.class) -@ComponentScan(basePackages = "com.alipay.sofa.koupleless.ext.web") public class ForwardAutoConfiguration { @Autowired private GatewayProperties gatewayProperties; + @PostConstruct + public void init() { + if (ArkUtils.isMasterBiz()) { + ArkClient.getEventAdminService().register(new CompositeBizForwardsHandler()); + } + } + /** *

forwards.

* - * @return a {@link com.alipay.sofa.koupleless.ext.web.gateway.Forwards} object + * @return a {@link Forwards} object */ @Bean public Forwards forwards() { diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItem.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItem.java similarity index 96% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItem.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItem.java index 9266e9fa7..fd3525df2 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItem.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItem.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import lombok.Getter; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItemComparator.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItemComparator.java similarity index 97% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItemComparator.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItemComparator.java index dae3e76eb..d5b51ac4e 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItemComparator.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItemComparator.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import lombok.AccessLevel; import lombok.Getter; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItems.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItems.java similarity index 93% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItems.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItems.java index 45279bd64..b8d27e395 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardItems.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardItems.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -41,8 +41,8 @@ public class ForwardItems { /** *

init.

* - * @param bean a {@link com.alipay.sofa.koupleless.ext.web.gateway.Forwards} object - * @param gatewayProperties a {@link com.alipay.sofa.koupleless.ext.web.gateway.GatewayProperties} object + * @param bean a {@link Forwards} object + * @param gatewayProperties a {@link GatewayProperties} object */ public static void init(Forwards bean, GatewayProperties gatewayProperties) { //load conf diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardPath.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardPath.java similarity index 93% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardPath.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardPath.java index c7202ec0b..c0ef70ec2 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardPath.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/ForwardPath.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import lombok.Data; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forwards.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forwards.java similarity index 95% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forwards.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forwards.java index 96d4bcec5..7b2b1f473 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/Forwards.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/Forwards.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; import org.springframework.util.StringUtils; @@ -55,7 +55,7 @@ public void setItems(List items) { * * @param host a {@link java.lang.String} object * @param path a {@link java.lang.String} object - * @return a {@link com.alipay.sofa.koupleless.ext.web.gateway.ForwardItem} object + * @return a {@link ForwardItem} object */ public ForwardItem getForwardItem(String host, String path) { String key = host + path; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/GatewayProperties.java b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/GatewayProperties.java similarity index 89% rename from koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/GatewayProperties.java rename to koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/GatewayProperties.java index 5ce72333c..5dd5de5e1 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/GatewayProperties.java +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/GatewayProperties.java @@ -14,9 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.koupleless.ext.web.gateway; +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; -import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/koupleless-ext/koupleless-ext-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/koupleless-ext/koupleless-ext-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..acd803110 --- /dev/null +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardAutoConfiguration \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep b/koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandlerTest.java b/koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandlerTest.java new file mode 100644 index 000000000..8bf0ac59d --- /dev/null +++ b/koupleless-ext/koupleless-ext-autoconfigure/src/test/java/com/alipay/sofa/koupleless/ext/autoconfigure/web/gateway/CompositeBizForwardsHandlerTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway; + +import com.alipay.sofa.ark.spi.event.biz.AfterBizStartupEvent; +import com.alipay.sofa.ark.spi.event.biz.BeforeBizStopEvent; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.koupleless.common.util.ArkUtils; +import com.alipay.sofa.koupleless.common.util.SpringUtils; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: CompositeBizForwardsHandlerTest.java, v 0.1 2024年11月08日 20:24 立蓬 Exp $ + */ +public class CompositeBizForwardsHandlerTest { + + @Test + public void testCompositeBizForwardsHandler() { + CompositeBizForwardsHandler handler = new CompositeBizForwardsHandler(); + + try (MockedStatic arkUtils = Mockito.mockStatic(ArkUtils.class)) { + // case1: master biz + arkUtils.when(ArkUtils::isMasterBiz).thenReturn(true); + handler.handleEvent(null); + + // case2: biz + arkUtils.when(ArkUtils::isMasterBiz).thenReturn(false); + Biz biz = Mockito.mock(Biz.class); + ClassLoader bizClassLoader = Mockito.mock(ClassLoader.class); + doReturn(bizClassLoader).when(biz).getBizClassLoader(); + + try (MockedStatic springUtils = Mockito.mockStatic(SpringUtils.class)) { + // case2.1: get bean null + springUtils.when(() -> SpringUtils.getBean(biz, "forwards")).thenReturn(null); + + handler.handleEvent(new AfterBizStartupEvent(biz)); + assertTrue(CompositeBizForwardsHandler.getBizForwards().isEmpty()); + + handler.handleEvent(new BeforeBizStopEvent(biz)); + assertTrue(CompositeBizForwardsHandler.getBizForwards().isEmpty()); + + // case2.2: get bean not null + springUtils.when(() -> SpringUtils.getBean(biz, "forwards")) + .thenReturn(new Forwards()); + + handler.handleEvent(new AfterBizStartupEvent(biz)); + assertEquals(1, CompositeBizForwardsHandler.getBizForwards().size()); + + handler.handleEvent(new BeforeBizStopEvent(biz)); + assertTrue(CompositeBizForwardsHandler.getBizForwards().isEmpty()); + + } + } + + } +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/pom.xml b/koupleless-ext/koupleless-ext-web-gateway/pom.xml index eba87a8f1..9be3476db 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/pom.xml +++ b/koupleless-ext/koupleless-ext-web-gateway/pom.xml @@ -50,6 +50,25 @@ fastjson
+ + com.alipay.sofa.koupleless + koupleless-ext-autoconfigure + ${revision} + + + + com.alipay.sofa + sofa-ark-spi + provided + + + + com.alipay.sofa.koupleless + koupleless-common + provided + + + org.mockito mockito-core diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/CrossContextConfiguration.java b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/CrossContextConfiguration.java index 086d7361a..495911556 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/CrossContextConfiguration.java +++ b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/CrossContextConfiguration.java @@ -16,12 +16,15 @@ */ package com.alipay.sofa.koupleless.ext.web.gateway; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardAutoConfiguration; import org.apache.catalina.Context; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** @@ -31,6 +34,8 @@ * @version 1.0.0 */ @Configuration +@AutoConfigureAfter(ForwardAutoConfiguration.class) +@ComponentScan(basePackages = "com.alipay.sofa.koupleless.ext.web") public class CrossContextConfiguration { /** *

tomcatCrossContextCustomizer.

diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardController.java b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardController.java index f25105623..412183799 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardController.java +++ b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardController.java @@ -16,6 +16,13 @@ */ package com.alipay.sofa.koupleless.ext.web.gateway; +import com.alipay.sofa.ark.api.ArkClient; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.koupleless.common.log.KouplelessLogger; +import com.alipay.sofa.koupleless.common.log.KouplelessLoggerFactory; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.CompositeBizForwardsHandler; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardItem; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.Forwards; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; @@ -30,6 +37,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; +import java.util.Map; /** *

ForwardController class.

@@ -40,11 +48,17 @@ @Controller @RequestMapping public class ForwardController { + private static final KouplelessLogger LOGGER = KouplelessLoggerFactory + .getLogger("web-gateway"); + @Autowired - private Forwards forwards; + private Forwards baseForwards; + + private Map bizForwards = CompositeBizForwardsHandler + .getBizForwards(); - private static final String SEPARATOR = "/"; - private static final String DOUBLE_SEPARATORS = SEPARATOR + SEPARATOR; + private static final String SEPARATOR = "/"; + private static final String DOUBLE_SEPARATORS = SEPARATOR + SEPARATOR; /** *

redirect.

@@ -73,7 +87,7 @@ public void redirect(HttpServletRequest request, if (!StringUtils.hasLength(sourcePath)) { sourcePath = Forwards.ROOT_PATH; } - ForwardItem forwardItem = forwards.getForwardItem(host, sourcePath); + ForwardItem forwardItem = getForwardItem(host, sourcePath); if (forwardItem == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } @@ -84,6 +98,10 @@ public void redirect(HttpServletRequest request, if (targetPath.startsWith(DOUBLE_SEPARATORS)) { targetPath = targetPath.substring(1); } + + LOGGER.info("uri with host {}, sourcePath {} will forward to {}", host, sourcePath, + contextPath + targetPath); + ServletContext currentContext = request.getServletContext(); ServletContext nextContext = currentContext.getContext(contextPath + targetPath); if (currentContext == nextContext) { @@ -92,4 +110,34 @@ public void redirect(HttpServletRequest request, RequestDispatcher dispatcher = nextContext.getRequestDispatcher(targetPath); dispatcher.forward(request, response); } + + /** + * Matching Rule: Preferentially apply the forward configuration of the biz, and if not available, match the forward configuration of base. + * @param host the host of uri + * @param sourcePath the path of uri + * @return com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardItem + */ + private ForwardItem getForwardItem(String host, String sourcePath) { + ForwardItem item; + + // match biz forward first + for (Map.Entry entry : bizForwards.entrySet()) { + item = entry.getValue().getForwardItem(host, sourcePath); + if (null != item) { + Biz biz = ArkClient.getBizManagerService().getBizByClassLoader(entry.getKey()); + LOGGER.info("biz {} forward configuration matches: {} {}", biz.getIdentity(), host, + sourcePath); + return item; + } + } + + // match base forward + item = baseForwards.getForwardItem(host, sourcePath); + + if (null != item) { + LOGGER.info("base forward configuration matches: {} {}", host, sourcePath); + } + + return item; + } } diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardsConfChangeListener.java b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardsConfChangeListener.java index a528a8e8b..51ab68bca 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardsConfChangeListener.java +++ b/koupleless-ext/koupleless-ext-web-gateway/src/main/java/com/alipay/sofa/koupleless/ext/web/gateway/ForwardsConfChangeListener.java @@ -16,6 +16,9 @@ */ package com.alipay.sofa.koupleless.ext.web.gateway; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardItems; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.Forwards; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.GatewayProperties; import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.model.ConfigChangeEvent; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/main/resources/META-INF/spring.factories b/koupleless-ext/koupleless-ext-web-gateway/src/main/resources/META-INF/spring.factories index 3ed4c28da..6df719094 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/main/resources/META-INF/spring.factories +++ b/koupleless-ext/koupleless-ext-web-gateway/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alipay.sofa.koupleless.ext.web.gateway.ForwardAutoConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alipay.sofa.koupleless.ext.web.gateway.CrossContextConfiguration \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardControllerTests.java b/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardControllerTests.java index a89568075..47c4bef26 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardControllerTests.java +++ b/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardControllerTests.java @@ -17,12 +17,21 @@ package com.alipay.sofa.koupleless.ext.web; import com.alibaba.fastjson.JSONArray; -import com.alipay.sofa.koupleless.ext.web.gateway.*; +import com.alipay.sofa.ark.api.ArkClient; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.ark.spi.service.biz.BizManagerService; +import com.alipay.sofa.koupleless.common.log.KouplelessLogger; +import com.alipay.sofa.koupleless.common.util.ReflectionUtils; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.Forward; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardItems; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.Forwards; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.GatewayProperties; +import com.alipay.sofa.koupleless.ext.web.gateway.ForwardController; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.web.server.ResponseStatusException; @@ -34,58 +43,75 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class ForwardControllerTests { - @InjectMocks - private ForwardAutoConfiguration configuration; - private String confPath = "forwards.yaml"; + private String baseConfPath = "base_forwards.yaml"; + + private String biz1ConfPath = "biz1_forwards.yaml"; + + private String biz2ConfPath = "biz2_forwards.yaml"; + + @Mock + private Biz biz1; + + @Mock + private Biz biz2; - private ForwardController controller = new ForwardController(); + @Mock + private ClassLoader biz1CL = Mockito.mock(ClassLoader.class); + + @Mock + private ClassLoader biz2CL = Mockito.mock(ClassLoader.class); + + @Mock + private BizManagerService bizManagerService; @Before - public void before() throws NoSuchFieldException, IllegalAccessException, IOException { - Field field = ForwardAutoConfiguration.class.getDeclaredField("gatewayProperties"); - field.setAccessible(true); - Yaml yaml = new Yaml(); - JSONArray array = yaml.loadAs( - ForwardControllerTests.class.getClassLoader().getResourceAsStream(confPath), - JSONArray.class); - GatewayProperties properties = new GatewayProperties(); - properties.setForwards(array.toJavaList(Forward.class)); - field.set(configuration, properties); + public void prepare() { + ArkClient.setBizManagerService(bizManagerService); + when(biz1.getIdentity()).thenReturn("biz1"); + when(biz2.getIdentity()).thenReturn("biz2"); - Forwards forwards = configuration.forwards(); - field = ForwardController.class.getDeclaredField("forwards"); - field.setAccessible(true); - field.set(controller, forwards); + when(bizManagerService.getBizByClassLoader(biz1CL)).thenReturn(biz1); + when(bizManagerService.getBizByClassLoader(biz2CL)).thenReturn(biz2); } @Test - public void testRedirect() throws IOException, ServletException { + public void testRedirectForwards() throws IOException, ServletException { + ForwardController controller = new ForwardController(); + ReflectionUtils.setField("baseForwards", controller, loadForwards(baseConfPath)); + ReflectionUtils.setField("bizForwards", controller, initBizForwards()); + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); ServletContext baseContext = Mockito.mock(ServletContext.class); - Mockito.when(request.getServletContext()).thenReturn(baseContext); + when(request.getServletContext()).thenReturn(baseContext); ServletContext context1 = Mockito.mock(ServletContext.class); RequestDispatcher dispatcher1 = Mockito.mock(RequestDispatcher.class); - Mockito.when(context1.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher1); + when(context1.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher1); ServletContext context2 = Mockito.mock(ServletContext.class); RequestDispatcher dispatcher2 = Mockito.mock(RequestDispatcher.class); - Mockito.when(context2.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher2); + when(context2.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher2); ServletContext context3 = Mockito.mock(ServletContext.class); RequestDispatcher dispatcher3 = Mockito.mock(RequestDispatcher.class); - Mockito.when(context3.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher3); + when(context3.getRequestDispatcher((Mockito.anyString()))).thenReturn(dispatcher3); - Mockito.when(baseContext.getContext(Mockito.anyString())).then((invocation) -> { + when(baseContext.getContext(Mockito.anyString())).then((invocation) -> { String uri = invocation.getArgument(0); + // test biz1 conf if (uri.startsWith("/test1/")) { return context1; } + + // test biz2 conf if (uri.startsWith("/test2/")) { return context2; } @@ -95,24 +121,51 @@ public void testRedirect() throws IOException, ServletException { return baseContext; }); - Mockito.when(request.getRequestURL()) - .thenReturn(new StringBuffer("http://test1.xxx.com/test2")); + // test biz1 conf + when(request.getRequestURL()).thenReturn(new StringBuffer("http://test1.xxx.com/test1/xx")); controller.redirect(request, response); - Mockito.verify(dispatcher2, Mockito.times(1)).forward(request, response); + Mockito.verify(dispatcher1, Mockito.times(1)).forward(request, response); - Mockito.when(request.getRequestURL()) - .thenReturn(new StringBuffer("http://test1.xxx.com/test1/xx")); + // test biz2 conf + when(request.getRequestURL()).thenReturn(new StringBuffer("http://test1.xxx.com/test2")); controller.redirect(request, response); - Mockito.verify(dispatcher1, Mockito.times(1)).forward(request, response); + Mockito.verify(dispatcher2, Mockito.times(1)).forward(request, response); - Mockito.when(request.getRequestURL()) - .thenReturn(new StringBuffer("http://test3.xxx.com/test1/xx")); + // test base conf + when(request.getRequestURL()).thenReturn(new StringBuffer("http://test3.xxx.com/test1/xx")); controller.redirect(request, response); Mockito.verify(dispatcher3, Mockito.times(1)).forward(request, response); - Mockito.when(request.getRequestURL()) - .thenReturn(new StringBuffer("http://test4.xxx.com/test1/xx")); + // test no conf + when(request.getRequestURL()) + .thenReturn(new StringBuffer("http://test100.xxx.com/test1/xx")); Assert.assertThrows(ResponseStatusException.class, () -> controller.redirect(request, response)); + + // test priority: biz conf > base conf + when(request.getRequestURL()).thenReturn(new StringBuffer("http://test5.xxx.com/xx")); + controller.redirect(request, response); + Mockito.verify(dispatcher1, Mockito.times(2)).forward(request, response); + } + + private Forwards loadForwards(String confPath) { + Yaml yaml = new Yaml(); + JSONArray array = yaml.loadAs( + ForwardControllerTests.class.getClassLoader().getResourceAsStream(confPath), + JSONArray.class); + + GatewayProperties properties = new GatewayProperties(); + properties.setForwards(array.toJavaList(Forward.class)); + + Forwards forwards = new Forwards(); + ForwardItems.init(forwards, properties); + return forwards; + } + + private Map initBizForwards() { + Map res = new HashMap<>(); + res.put(biz1CL, loadForwards(biz1ConfPath)); + res.put(biz2CL, loadForwards(biz2ConfPath)); + return res; } } \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardsConfChangeListenerTests.java b/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardsConfChangeListenerTests.java index 7511f5ab8..ec6d83c82 100644 --- a/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardsConfChangeListenerTests.java +++ b/koupleless-ext/koupleless-ext-web-gateway/src/test/java/com/alipay/sofa/koupleless/ext/web/ForwardsConfChangeListenerTests.java @@ -16,10 +16,10 @@ */ package com.alipay.sofa.koupleless.ext.web; -import com.alipay.sofa.koupleless.ext.web.gateway.ForwardItem; -import com.alipay.sofa.koupleless.ext.web.gateway.Forwards; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.ForwardItem; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.Forwards; +import com.alipay.sofa.koupleless.ext.autoconfigure.web.gateway.GatewayProperties; import com.alipay.sofa.koupleless.ext.web.gateway.ForwardsConfChangeListener; -import com.alipay.sofa.koupleless.ext.web.gateway.GatewayProperties; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import org.junit.Assert; import org.junit.Before; diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/base_forwards.yaml b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/base_forwards.yaml new file mode 100644 index 000000000..54b9b0316 --- /dev/null +++ b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/base_forwards.yaml @@ -0,0 +1,6 @@ +- contextPath: test3 + hosts: + - test3 +- contextPath: test3 + hosts: + - test5 \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz1_forwards.yaml b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz1_forwards.yaml new file mode 100644 index 000000000..1ca9a902b --- /dev/null +++ b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz1_forwards.yaml @@ -0,0 +1,8 @@ +- contextPath: test1 + hosts: + - test1 + paths: + - from: /test1 +- contextPath: test1 + hosts: + - test5 \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz2_forwards.yaml b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz2_forwards.yaml new file mode 100644 index 000000000..ece389e85 --- /dev/null +++ b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/biz2_forwards.yaml @@ -0,0 +1,5 @@ +- contextPath: test2 + paths: + - from: /test2 + - from: /api/test2 + - from: /api-test2 \ No newline at end of file diff --git a/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/forwards.yaml b/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/forwards.yaml deleted file mode 100644 index fc8c78fd1..000000000 --- a/koupleless-ext/koupleless-ext-web-gateway/src/test/resources/forwards.yaml +++ /dev/null @@ -1,13 +0,0 @@ -- contextPath: test1 - hosts: - - test1 - paths: - - from: /test1 -- contextPath: test2 - paths: - - from: /test2 - - from: /api/test2 - - from: /api-test2 -- contextPath: test3 - hosts: - - test3 \ No newline at end of file diff --git a/koupleless-ext/pom.xml b/koupleless-ext/pom.xml index baf93326e..8671e821c 100644 --- a/koupleless-ext/pom.xml +++ b/koupleless-ext/pom.xml @@ -17,6 +17,7 @@ koupleless-test-suite koupleless-base-loader koupleless-build-plugin + koupleless-ext-autoconfigure koupleless-ext-module-auto-convertor archetype/koupleless-common-module-archetype