feat:support service contract reporting. (#1135)
parent
ac5018867d
commit
79a03c2800
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>spring-cloud-tencent</artifactId>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
|
||||||
|
<name>Spring Cloud Starter Tencent Polaris Contract</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring Cloud Tencent dependencies start -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Cloud Tencent dependencies end -->
|
||||||
|
|
||||||
|
<!-- Spring cloud dependencies start -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring cloud dependencies start -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-boot-starter</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>swagger-models</artifactId>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
<artifactId>swagger-models</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.tencent.cloud.common.util.JacksonUtils;
|
||||||
|
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
|
||||||
|
import com.tencent.polaris.api.core.ProviderAPI;
|
||||||
|
import com.tencent.polaris.api.plugin.server.InterfaceDescriptor;
|
||||||
|
import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest;
|
||||||
|
import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse;
|
||||||
|
import io.swagger.models.HttpMethod;
|
||||||
|
import io.swagger.models.Operation;
|
||||||
|
import io.swagger.models.Path;
|
||||||
|
import io.swagger.models.Swagger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import springfox.documentation.service.Documentation;
|
||||||
|
import springfox.documentation.spring.web.DocumentationCache;
|
||||||
|
import springfox.documentation.spring.web.json.JsonSerializer;
|
||||||
|
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> {
|
||||||
|
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class);
|
||||||
|
private final ServiceModelToSwagger2Mapper swagger2Mapper;
|
||||||
|
private final DocumentationCache documentationCache;
|
||||||
|
private final JsonSerializer jsonSerializer;
|
||||||
|
private final String groupName;
|
||||||
|
|
||||||
|
private final ProviderAPI providerAPI;
|
||||||
|
|
||||||
|
private final PolarisDiscoveryProperties polarisDiscoveryProperties;
|
||||||
|
|
||||||
|
public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper,
|
||||||
|
JsonSerializer jsonSerializer, String groupName, ProviderAPI providerAPI,
|
||||||
|
PolarisDiscoveryProperties polarisDiscoveryProperties) {
|
||||||
|
this.swagger2Mapper = swagger2Mapper;
|
||||||
|
this.documentationCache = documentationCache;
|
||||||
|
this.jsonSerializer = jsonSerializer;
|
||||||
|
this.groupName = groupName;
|
||||||
|
this.providerAPI = providerAPI;
|
||||||
|
this.polarisDiscoveryProperties = polarisDiscoveryProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) {
|
||||||
|
try {
|
||||||
|
Documentation documentation = documentationCache.documentationByGroup(groupName);
|
||||||
|
Swagger swagger = swagger2Mapper.mapDocumentation(documentation);
|
||||||
|
if (swagger != null) {
|
||||||
|
ReportServiceContractRequest request = new ReportServiceContractRequest();
|
||||||
|
request.setName(polarisDiscoveryProperties.getService());
|
||||||
|
request.setNamespace(polarisDiscoveryProperties.getNamespace());
|
||||||
|
request.setService(polarisDiscoveryProperties.getService());
|
||||||
|
request.setProtocol("http");
|
||||||
|
request.setVersion(polarisDiscoveryProperties.getVersion());
|
||||||
|
List<InterfaceDescriptor> interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger);
|
||||||
|
request.setInterfaceDescriptors(interfaceDescriptorList);
|
||||||
|
ReportServiceContractResponse response = providerAPI.reportServiceContract(request);
|
||||||
|
LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.",
|
||||||
|
request.getNamespace(), request.getName(), request.getService(), request.getProtocol(),
|
||||||
|
request.getVersion(), request.getInterfaceDescriptors().size());
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
String jsonValue = JacksonUtils.serialize2Json(swagger);
|
||||||
|
LOG.debug("OpenApi json data: {}", jsonValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all()
|
||||||
|
.keySet(), groupName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
LOG.error("Report contract failed.", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InterfaceDescriptor> getInterfaceDescriptorFromSwagger(Swagger swagger) {
|
||||||
|
List<InterfaceDescriptor> interfaceDescriptorList = new ArrayList<>();
|
||||||
|
Map<String, Path> paths = swagger.getPaths();
|
||||||
|
for (Map.Entry<String, Path> p : paths.entrySet()) {
|
||||||
|
Path path = p.getValue();
|
||||||
|
Map<String, Operation> operationMap = getOperationMapFromPath(path);
|
||||||
|
if (CollectionUtils.isEmpty(operationMap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Operation> o : operationMap.entrySet()) {
|
||||||
|
InterfaceDescriptor interfaceDescriptor = new InterfaceDescriptor();
|
||||||
|
interfaceDescriptor.setPath(p.getKey());
|
||||||
|
interfaceDescriptor.setMethod(o.getKey());
|
||||||
|
interfaceDescriptor.setContent(JacksonUtils.serialize2Json(p.getValue()));
|
||||||
|
interfaceDescriptorList.add(interfaceDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return interfaceDescriptorList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Operation> getOperationMapFromPath(Path path) {
|
||||||
|
Map<String, Operation> operationMap = new HashMap<>();
|
||||||
|
|
||||||
|
if (path.getGet() != null) {
|
||||||
|
operationMap.put(HttpMethod.GET.name(), path.getGet());
|
||||||
|
}
|
||||||
|
if (path.getPut() != null) {
|
||||||
|
operationMap.put(HttpMethod.PUT.name(), path.getPut());
|
||||||
|
}
|
||||||
|
if (path.getPost() != null) {
|
||||||
|
operationMap.put(HttpMethod.POST.name(), path.getPost());
|
||||||
|
}
|
||||||
|
if (path.getHead() != null) {
|
||||||
|
operationMap.put(HttpMethod.HEAD.name(), path.getHead());
|
||||||
|
}
|
||||||
|
if (path.getDelete() != null) {
|
||||||
|
operationMap.put(HttpMethod.DELETE.name(), path.getDelete());
|
||||||
|
}
|
||||||
|
if (path.getPatch() != null) {
|
||||||
|
operationMap.put(HttpMethod.PATCH.name(), path.getPatch());
|
||||||
|
}
|
||||||
|
if (path.getOptions() != null) {
|
||||||
|
operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
return operationMap;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
|
||||||
|
public class PolarisSwaggerApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent startingEvent) {
|
||||||
|
SpringApplication application = startingEvent.getSpringApplication();
|
||||||
|
Class<?> mainClass = application.getMainApplicationClass();
|
||||||
|
if (mainClass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SwaggerContext.setAttribute(String.format("$%s", "MainClass"), mainClass);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public final class SwaggerContext {
|
||||||
|
private static final ConcurrentHashMap<String, Object> attribute = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private SwaggerContext() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setAttribute(String key, Object value) {
|
||||||
|
attribute.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object getAttribute(String key) {
|
||||||
|
return attribute.get(key);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for contract properties.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public interface ContractProperties {
|
||||||
|
|
||||||
|
boolean isEnabled();
|
||||||
|
|
||||||
|
void setEnabled(boolean enabled);
|
||||||
|
|
||||||
|
String getBasePackage();
|
||||||
|
|
||||||
|
void setBasePackage(String basePackage);
|
||||||
|
|
||||||
|
String getExcludePath();
|
||||||
|
|
||||||
|
void setExcludePath(String excludePath);
|
||||||
|
|
||||||
|
String getGroup();
|
||||||
|
|
||||||
|
void setGroup(String group);
|
||||||
|
|
||||||
|
String getBasePath();
|
||||||
|
|
||||||
|
void setBasePath(String basePath);
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend contract properties.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public interface ExtendedContractProperties extends ContractProperties {
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.tencent.cloud.common.constant.OrderConstant;
|
||||||
|
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
|
||||||
|
import com.tencent.polaris.factory.config.ConfigurationImpl;
|
||||||
|
import com.tencent.polaris.factory.config.provider.RegisterConfigImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier of service contract.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class PolarisContractModifier implements PolarisConfigModifier {
|
||||||
|
|
||||||
|
private final PolarisContractProperties polarisContractProperties;
|
||||||
|
|
||||||
|
public PolarisContractModifier(PolarisContractProperties polarisContractProperties) {
|
||||||
|
this.polarisContractProperties = polarisContractProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modify(ConfigurationImpl configuration) {
|
||||||
|
List<RegisterConfigImpl> registerConfigs = configuration.getProvider().getRegisters();
|
||||||
|
for (RegisterConfigImpl registerConfig : registerConfigs) {
|
||||||
|
registerConfig.setReportServiceContractEnable(polarisContractProperties.isEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return OrderConstant.Modifier.SERVICE_CONTRACT_ORDER;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for Polaris contract.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("spring.cloud.polaris.contract")
|
||||||
|
public class PolarisContractProperties implements ContractProperties {
|
||||||
|
|
||||||
|
private final ExtendedContractProperties extendContractProperties;
|
||||||
|
|
||||||
|
private boolean enabled = true;
|
||||||
|
/**
|
||||||
|
* Packages to be scanned. Split by ",".
|
||||||
|
*/
|
||||||
|
private String basePackage;
|
||||||
|
/**
|
||||||
|
* Paths to be excluded. Split by ",".
|
||||||
|
*/
|
||||||
|
private String excludePath;
|
||||||
|
/**
|
||||||
|
* Group to create swagger docket.
|
||||||
|
*/
|
||||||
|
private String group = "default";
|
||||||
|
/**
|
||||||
|
* Base paths to be scanned. Split by ",".
|
||||||
|
*/
|
||||||
|
private String basePath = "/**";
|
||||||
|
|
||||||
|
public PolarisContractProperties(@Nullable ExtendedContractProperties extendContractProperties) {
|
||||||
|
this.extendContractProperties = extendContractProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
if (Objects.nonNull(extendContractProperties)) {
|
||||||
|
return extendContractProperties.isEnabled();
|
||||||
|
}
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBasePackage() {
|
||||||
|
if (Objects.nonNull(extendContractProperties)) {
|
||||||
|
return extendContractProperties.getBasePackage();
|
||||||
|
}
|
||||||
|
return basePackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBasePackage(String basePackage) {
|
||||||
|
this.basePackage = basePackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExcludePath() {
|
||||||
|
if (Objects.nonNull(extendContractProperties)) {
|
||||||
|
return extendContractProperties.getExcludePath();
|
||||||
|
}
|
||||||
|
return excludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExcludePath(String excludePath) {
|
||||||
|
this.excludePath = excludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getGroup() {
|
||||||
|
if (Objects.nonNull(extendContractProperties)) {
|
||||||
|
return extendContractProperties.getGroup();
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGroup(String group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBasePath() {
|
||||||
|
if (Objects.nonNull(extendContractProperties)) {
|
||||||
|
return extendContractProperties.getBasePath();
|
||||||
|
}
|
||||||
|
return basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBasePath(String basePath) {
|
||||||
|
this.basePath = basePath;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto configuration for Polaris contract properties.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnPolarisEnabled
|
||||||
|
public class PolarisContractPropertiesAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public PolarisContractProperties polarisContractProperties(@Nullable ExtendedContractProperties extendedContractProperties) {
|
||||||
|
return new PolarisContractProperties(extendedContractProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public PolarisContractModifier polarisContractModifier(PolarisContractProperties polarisContractProperties) {
|
||||||
|
return new PolarisContractModifier(polarisContractProperties);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap configuration for Polaris contract properties.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnProperty("spring.cloud.polaris.enabled")
|
||||||
|
@Import(PolarisContractPropertiesAutoConfiguration.class)
|
||||||
|
public class PolarisContractPropertiesBootstrapConfiguration {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.config;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
|
||||||
|
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
|
||||||
|
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
|
||||||
|
import com.tencent.cloud.polaris.contract.PolarisContractReporter;
|
||||||
|
import com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener;
|
||||||
|
import com.tencent.cloud.polaris.contract.utils.PackageUtil;
|
||||||
|
import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration;
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.service.Contact;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.DocumentationCache;
|
||||||
|
import springfox.documentation.spring.web.json.JsonSerializer;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnPolarisEnabled
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true)
|
||||||
|
@Import(OpenApiAutoConfiguration.class)
|
||||||
|
public class PolarisSwaggerAutoConfiguration {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// After springboot2.6.x, the default path matching strategy of spring MVC is changed from ANT_PATH_MATCHER
|
||||||
|
// mode to PATH_PATTERN_PARSER mode, causing an error. The solution is to switch to the original ANT_PATH_MATCHER mode.
|
||||||
|
System.setProperty("spring.mvc.pathmatch.matching-strategy", "ant-path-matcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Docket polarisDocket(PolarisContractProperties polarisContractProperties) {
|
||||||
|
List<Predicate<String>> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath());
|
||||||
|
List<Predicate<String>> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath());
|
||||||
|
String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage());
|
||||||
|
|
||||||
|
Predicate<String> basePathListOr = null;
|
||||||
|
for (Predicate<String> basePathPredicate : basePathList) {
|
||||||
|
if (basePathListOr == null) {
|
||||||
|
basePathListOr = basePathPredicate;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
basePathListOr = basePathListOr.or(basePathPredicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Predicate<String> excludePathListOr = null;
|
||||||
|
for (Predicate<String> excludePathPredicate : excludePathList) {
|
||||||
|
if (excludePathListOr == null) {
|
||||||
|
excludePathListOr = excludePathPredicate;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
excludePathListOr = excludePathListOr.or(excludePathPredicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Predicate<String> pathsPredicate = basePathListOr;
|
||||||
|
|
||||||
|
if (excludePathListOr != null) {
|
||||||
|
excludePathListOr = excludePathListOr.negate();
|
||||||
|
pathsPredicate = pathsPredicate.and(excludePathListOr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.select()
|
||||||
|
.apis(PackageUtil.basePackage(basePackage))
|
||||||
|
.paths(pathsPredicate)
|
||||||
|
.build()
|
||||||
|
.groupName(polarisContractProperties.getGroup())
|
||||||
|
.enable(polarisContractProperties.isEnabled())
|
||||||
|
.directModelSubstitute(LocalDate.class, Date.class)
|
||||||
|
.apiInfo(new ApiInfoBuilder()
|
||||||
|
.title("Polaris Swagger API")
|
||||||
|
.description("This is to show polaris api description.")
|
||||||
|
.license("BSD-3-Clause")
|
||||||
|
.licenseUrl("https://opensource.org/licenses/BSD-3-Clause")
|
||||||
|
.termsOfServiceUrl("")
|
||||||
|
.version("1.0.0")
|
||||||
|
.contact(new Contact("", "", ""))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnBean(Docket.class)
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public PolarisContractReporter polarisApiMetadataGrapher(DocumentationCache documentationCache,
|
||||||
|
ServiceModelToSwagger2Mapper swagger2Mapper, JsonSerializer jsonSerializer,
|
||||||
|
PolarisContractProperties polarisContractProperties, PolarisSDKContextManager polarisSDKContextManager,
|
||||||
|
PolarisDiscoveryProperties polarisDiscoveryProperties) {
|
||||||
|
return new PolarisContractReporter(documentationCache, swagger2Mapper, jsonSerializer,
|
||||||
|
polarisContractProperties.getGroup(), polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public PolarisSwaggerApplicationListener polarisSwaggerApplicationListener() {
|
||||||
|
return new PolarisSwaggerApplicationListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create when web application type is SERVLET.
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||||
|
protected static class SwaggerServletConfig {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create when web application type is REACTIVE.
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||||
|
protected static class SwaggerReactiveConfig {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* 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.tencent.cloud.polaris.contract.utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.tencent.cloud.polaris.contract.SwaggerContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import springfox.documentation.RequestHandler;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import static com.google.common.base.Optional.fromNullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Util for package processing.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public final class PackageUtil {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class);
|
||||||
|
|
||||||
|
private static final String SPLITTER = ",";
|
||||||
|
|
||||||
|
|
||||||
|
private PackageUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<RequestHandler> basePackage(String basePackage) {
|
||||||
|
return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<Class<?>> declaringClass(RequestHandler input) {
|
||||||
|
if (input == null) {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
return fromNullable(input.declaringClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<Class<?>, Boolean> handlerPackage(String basePackage, String splitter) {
|
||||||
|
return input -> {
|
||||||
|
try {
|
||||||
|
if (StringUtils.isEmpty(basePackage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String[] packages = basePackage.trim().split(splitter);
|
||||||
|
// Loop to determine matching
|
||||||
|
for (String strPackage : packages) {
|
||||||
|
if (input == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Package pkg = input.getPackage();
|
||||||
|
if (pkg == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = pkg.getName();
|
||||||
|
if (StringUtils.isEmpty(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean isMatch = name.startsWith(strPackage);
|
||||||
|
if (isMatch) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.error("handler package error", e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Predicate<String>> getExcludePathPredicates(String excludePath) {
|
||||||
|
List<Predicate<String>> excludePathList = new ArrayList<>();
|
||||||
|
if (StringUtils.isEmpty(excludePath)) {
|
||||||
|
return excludePathList;
|
||||||
|
}
|
||||||
|
String[] exs = excludePath.split(SPLITTER);
|
||||||
|
for (String ex : exs) {
|
||||||
|
if (!StringUtils.isEmpty(ex)) {
|
||||||
|
excludePathList.add(PathSelectors.ant(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return excludePathList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Predicate<String>> getBasePathPredicates(String basePath) {
|
||||||
|
List<Predicate<String>> basePathList = new ArrayList<>();
|
||||||
|
if (!StringUtils.isEmpty(basePath)) {
|
||||||
|
String[] bps = basePath.split(SPLITTER);
|
||||||
|
for (String bp : bps) {
|
||||||
|
if (!StringUtils.isEmpty(bp)) {
|
||||||
|
basePathList.add(PathSelectors.ant(bp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (basePathList.isEmpty()) {
|
||||||
|
basePathList.add(PathSelectors.ant("/**"));
|
||||||
|
}
|
||||||
|
return basePathList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String scanPackage(String configBasePackage) {
|
||||||
|
String validScanPackage;
|
||||||
|
// Externally configured scan package
|
||||||
|
Set<String> configPackageSet = new HashSet<>();
|
||||||
|
if (!StringUtils.isEmpty(configBasePackage)) {
|
||||||
|
configPackageSet.addAll(Arrays.asList(configBasePackage.split(SPLITTER)));
|
||||||
|
}
|
||||||
|
Object mainClz = SwaggerContext.getAttribute(String.format("$%s", "MainClass"));
|
||||||
|
// Verification of the valid path of MainClass
|
||||||
|
if (mainClz != null) {
|
||||||
|
Set<String> autoDetectPackageSet = parseDefaultScanPackage((Class<?>) mainClz);
|
||||||
|
if (LOG.isInfoEnabled() && !autoDetectPackageSet.isEmpty()) {
|
||||||
|
LOG.info("Auto detect default swagger scan packages: {}",
|
||||||
|
String.join(SPLITTER, autoDetectPackageSet).trim());
|
||||||
|
}
|
||||||
|
Set<String> validScanPackageSet = merge(configPackageSet, autoDetectPackageSet);
|
||||||
|
validScanPackage = String.join(SPLITTER, validScanPackageSet).trim();
|
||||||
|
if (LOG.isInfoEnabled() && !StringUtils.isEmpty(validScanPackage)) {
|
||||||
|
LOG.info("Swagger scan valid packages: {}", validScanPackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If there is no MainClass, the configured path is used for scanning
|
||||||
|
validScanPackage = String.join(SPLITTER, configPackageSet);
|
||||||
|
if (LOG.isWarnEnabled()) {
|
||||||
|
LOG.warn("Cannot detect main class, swagger scanning packages is set to: {}",
|
||||||
|
validScanPackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validScanPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> merge(Set<String> configPackageSet, Set<String> autoDetectPackageSet) {
|
||||||
|
if (configPackageSet == null || configPackageSet.size() == 0) {
|
||||||
|
return autoDetectPackageSet;
|
||||||
|
}
|
||||||
|
return configPackageSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Set<String> parseDefaultScanPackage(Class<?> mainClass) {
|
||||||
|
Set<String> packageSets = new HashSet<>();
|
||||||
|
String defaultPackage = mainClass.getPackage().getName();
|
||||||
|
try {
|
||||||
|
boolean springBootEnv = true;
|
||||||
|
try {
|
||||||
|
Class.forName("org.springframework.boot.autoconfigure.SpringBootApplication");
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
LOG.info("Can not load annotation @SpringBootApplication, " +
|
||||||
|
"current environment is not in spring boot framework. ");
|
||||||
|
springBootEnv = false;
|
||||||
|
}
|
||||||
|
if (!springBootEnv) {
|
||||||
|
packageSets.add(defaultPackage);
|
||||||
|
return packageSets;
|
||||||
|
}
|
||||||
|
SpringBootApplication bootAnnotation = mainClass.getAnnotation(SpringBootApplication.class);
|
||||||
|
Class<?>[] baseClassPackages;
|
||||||
|
String[] basePackages;
|
||||||
|
if (bootAnnotation == null) {
|
||||||
|
packageSets.add(defaultPackage);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// baseClassPackages annotation
|
||||||
|
baseClassPackages = bootAnnotation.scanBasePackageClasses();
|
||||||
|
for (Class<?> clz : baseClassPackages) {
|
||||||
|
packageSets.add(clz.getPackage().getName());
|
||||||
|
}
|
||||||
|
// basePackage annotation
|
||||||
|
basePackages = bootAnnotation.scanBasePackages();
|
||||||
|
packageSets.addAll(Arrays.asList(basePackages));
|
||||||
|
// When basePackage and baseClassPackages are both empty, the package path where the MainClass class is located is used by default.
|
||||||
|
if (packageSets.isEmpty()) {
|
||||||
|
packageSets.add(defaultPackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
LOG.warn("Swagger scan package is empty and auto detect main class occur exception: {}",
|
||||||
|
t.getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
return packageSets;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
com.tencent.cloud.polaris.contract.config.PolarisSwaggerAutoConfiguration,\
|
||||||
|
com.tencent.cloud.polaris.contract.config.PolarisContractProperties
|
||||||
|
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||||
|
com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration
|
||||||
|
org.springframework.context.ApplicationListener=\
|
||||||
|
com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener
|
Loading…
Reference in new issue