Skip to content

Commit

Permalink
✨ add PanGuScan module
Browse files Browse the repository at this point in the history
  • Loading branch information
yuebaix committed Sep 5, 2021
1 parent 096e1c6 commit 0bfe83b
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 1 deletion.
10 changes: 10 additions & 0 deletions pangu-common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
plugins {
id 'java'
id 'java-library'
}

dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

api 'com.fasterxml.jackson.core:jackson-databind'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.yuebaix.pangu.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.SneakyThrows;

public final class JacksonUtil {
private static final ObjectMapper objectMapperHolder;
static {
ObjectMapper ob = new ObjectMapper();
//允许序列化空POJO
ob.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//把时间按照字符串输出
ob.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//POJO中的null值不输出
ob.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//在遇到未知属性的时候不抛出异常
ob.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapperHolder = ob;
}
private JacksonUtil() {}

public static ObjectMapper getObjectMapperHolder() {
return objectMapperHolder;
}

@SneakyThrows
public static String write(Object obj) {
return getObjectMapperHolder().writeValueAsString(obj);
}

@SneakyThrows
public static <T> T read(String cnt, Class<T> clazz) {
return getObjectMapperHolder().readValue(cnt, clazz);
}

@SneakyThrows
public static <T> T read(String cnt, TypeReference<T> typeRef) {
return getObjectMapperHolder().readValue(cnt, typeRef);
}
}
5 changes: 5 additions & 0 deletions pangu-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@ plugins {
}

dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

api project(':pangu-common')
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@

public interface PanGuStarterConst {
String PAN_GU_STARTER_ENABLED = "pangu.starter.enabled";

String PAN_GU_SCAN_ACTIVE = "pangu.scan.active";
String PAN_GU_SCAN_CONFIG = "pangu.scan.config";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.yuebaix.pangu.support;

import com.fasterxml.jackson.core.type.TypeReference;
import com.yuebaix.pangu.autoconfigure.common.PanGuStarterConst;
import com.yuebaix.pangu.common.util.JacksonUtil;
import com.yuebaix.pangu.core.PanGuCoreConst;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* desc: a brief configurable PatternTypeFilter based on @ComponentScan
*
* usage:
*
* # 1.setting
* # active config profile
* pangu.scan.active=all
* # config detail.profile name as key, json as value.first exclude then include.
* pangu.scan.config={"all":{"exclude":[".*\.modulePkg\.pkg\.className"], "include":[".*\.modulePkg\.pkg\..*"]}}
*
* # 2.code (better right above @SpringBootApplication)
* @ComponentScan(
* useDefaultFilters = false,
* includeFilters = {
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = PanGuScan.IncludeTypeFilter.class)
* },
* excludeFilters = {
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = PanGuScan.ExcludeTypeFilter.class)
* }
* )
* @SpringBootApplication
* public class App {
* public static void main(String[] args) {
* SpringApplication.run(App.class, args);
* }
* }
*/
@Slf4j
public abstract class PanGuScan implements EnvironmentAware {
private static final int CHOICE_EXCLUDE = 0;
private static final int CHOICE_INCLUDE = 1;

private String activeProfile;
private PanGuScanTypeFilterPatternConfig activePatternConfig;

@Override
public void setEnvironment(Environment environment) {
String active = environment.getProperty(PanGuStarterConst.PAN_GU_SCAN_ACTIVE);
if (!StringUtils.isEmpty(active)) {
String config = environment.getProperty(PanGuStarterConst.PAN_GU_SCAN_CONFIG);
if (!StringUtils.isEmpty(active)) {
Map<String, PanGuScanTypeFilterConfig> configProfiles = JacksonUtil.read(config, new TypeReference<Map<String, PanGuScanTypeFilterConfig>>(){});
PanGuScanTypeFilterConfig activeConfig = configProfiles.get(active);
if (activeConfig != null) {
PanGuScanTypeFilterPatternConfig activePatternConfig = fromConfig(activeConfig);
this.activeProfile = active;
this.activePatternConfig = activePatternConfig;
log.debug(PanGuCoreConst.PAN_GU_TRACE_PREFIX + "PanGuScan " + this.getClass().getSimpleName() +
" Initialized | active:{} | config:{}", active, JacksonUtil.write(activeConfig));
}
}
}
}

protected boolean matchInternal(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory, int choice) {
String className = metadataReader.getClassMetadata().getClassName();
if (CHOICE_EXCLUDE == choice) {
for (Pattern pattern : activePatternConfig.getExcludePattern()) {
if (isMatch(pattern, className)) {
log.debug(PanGuCoreConst.PAN_GU_TRACE_PREFIX + "PanGuScan Exclude | active:{} | pattern:{} | className:{}",
activeProfile, pattern.pattern(), className);
return true;
}
}
} else if (CHOICE_INCLUDE == choice) {
for (Pattern pattern : activePatternConfig.getIncludePattern()) {
if (isMatch(pattern, className)) {
log.debug(PanGuCoreConst.PAN_GU_TRACE_PREFIX + "PanGuScan Include | active:{} | pattern:{} | className:{}",
activeProfile, pattern.pattern(), className);
return true;
}
}
}
return false;
}

private boolean isMatch(Pattern pattern, CharSequence content) {
if (content == null || pattern == null) {
return false;
}
return pattern.matcher(content).matches();
}

private PanGuScanTypeFilterPatternConfig fromConfig(PanGuScanTypeFilterConfig config) {
PanGuScanTypeFilterPatternConfig patternConfig = new PanGuScanTypeFilterPatternConfig();
if (config != null) {
List<String> exclude = config.getExclude();
patternConfig.setExcludePattern(strToPattern(exclude));
List<String> include = config.getInclude();
patternConfig.setIncludePattern(strToPattern(include));
}
return patternConfig;
}

private List<Pattern> strToPattern(List<String> strList) {
List<Pattern> patternList = Collections.emptyList();
if (!CollectionUtils.isEmpty(strList)) {
patternList = strList.stream().map(Pattern::compile).collect(Collectors.toList());
}
return patternList;
}

@Data
private static final class PanGuScanTypeFilterConfig {
private List<String> include;
private List<String> exclude;
}

@Data
private static final class PanGuScanTypeFilterPatternConfig {
private List<Pattern> includePattern;
private List<Pattern> excludePattern;
}

public static final class ExcludeTypeFilter extends PanGuScan implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return matchInternal(metadataReader, metadataReaderFactory, CHOICE_EXCLUDE);
}
}

public static final class IncludeTypeFilter extends PanGuScan implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return matchInternal(metadataReader, metadataReaderFactory, CHOICE_INCLUDE);
}
}
}
1 change: 1 addition & 0 deletions pangu-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ dependencies {
implementation 'org.mapstruct:mapstruct'
annotationProcessor 'org.mapstruct:mapstruct-processor'

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

//implementation project(':pangu-web')
//implementation project(':pangu-spring-boot-starter')
Expand Down
12 changes: 12 additions & 0 deletions pangu-test/src/main/java/com/yuebaix/pangu/test/PanGuTestApp.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package com.yuebaix.pangu.test;

import com.yuebaix.pangu.support.PanGuScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

@ComponentScan(
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = PanGuScan.IncludeTypeFilter.class)
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = PanGuScan.ExcludeTypeFilter.class)
}
)
@SpringBootApplication
public class PanGuTestApp {
public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.yuebaix.pangu.test.controller.demo;

import com.yuebaix.pangu.common.util.JacksonUtil;
import com.yuebaix.pangu.web.base.BaseReq;
import com.yuebaix.pangu.web.base.BaseResp;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;

@RestController
@RequestMapping("/demo/demo")
public class DemoController {
@ApiOperation("示例")
@GetMapping("/check")
public BaseResp check(BaseReq req) {
return BaseResp.success(JacksonUtil.write(Collections.singletonMap("say", "demo")));
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package com.yuebaix.pangu.test.controller.demo;

import com.yuebaix.pangu.common.util.JacksonUtil;
import com.yuebaix.pangu.web.base.BaseReq;
import com.yuebaix.pangu.web.base.BaseResp;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;

@RestController
@RequestMapping("/demo/test")
public class TestController {
@ApiOperation("测试")
@GetMapping("/check")
public BaseResp check(BaseReq req) {
return BaseResp.success();
return BaseResp.success(JacksonUtil.write(Collections.singletonMap("say", "test")));
}
}
3 changes: 3 additions & 0 deletions pangu-test/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
logging.level.com.yuebaix.pangu = debug

#springfox.documentation.swagger-ui.enabled=true

pangu.scan.active=all
pangu.scan.config={"all":{"exclude":[], "include":[".*\.pangu\.test\..*"]}}

0 comments on commit 0bfe83b

Please sign in to comment.